From: "pyromaniac (Arkadiy Zabazhanov)" Date: 2022-10-17T16:12:37+00:00 Subject: [ruby-core:110368] [Ruby master Feature#17576] Partial Functions (procs, lambdas) Issue #17576 has been updated by pyromaniac (Arkadiy Zabazhanov). Isn't the topic starter talking about pattern arguments for function? This is something I'm personally looking froward to. It is similar to Elixir's functions pattern matching and increases the expressiveness of the language by order of magnitude. For example, I have some complex entity and have a handler that does something with its attributes: ``` ruby Discount = Data.define(:name, :code, :percentage) Product = Data.define(:title, :price) def calculate_discount({ price: Money & 0.. }, { percentage: BigDecimal & 0..100 }) price * percentage end ``` Now I have a loosely coupled handler that only specifies the requirements for the passed object with a pattern. You can even think of it as of a simple type system. ``` ruby calculate_discount(product, discount) ``` Btw, while imagining this example I also thought maybe it is possible to use boolean-like pattern combinations, we have `|` user there already to alternate patterns, so why don't combine them with `&`? This implementation is an equivalent of: ```ruby def calculate_discount(product, discount) product => { price: Money & 0.. } discount => { percentage: BigDecimal & 0..100 } price * percentage end ``` When and if there will be a way of putting a pattern into a variable somehow, I would do something like: ```ruby def self.defpm(method_name, pattern, &block) @method_patterns ||= {} @method_patterns[method_name] ||= {} @method_patterns[method_name][pattern] = block unless method_defined?(method_name) define_method(method_name, *args) do pattern, block = self.class.method_pattern[method_name].detect do |pattern, block| args in pattern end block.call(*args) end end end ``` This code would not do the trick by I hope you got the idea: we define multiple methods with the same name but different argument patterns using the DSL and then the first matching pattern and its corresponding block is used when the method is called. We might also need some pattern match result object like we have for regexp match. Later, this can be turned from a DSL to a first-class syntax like: ``` defpm foo({ bar: 0.. }) end ``` The bottom line is that in Elixir this pattern matching for method signature is very expressive and makes code writing and support a way more joyful process. ---------------------------------------- Feature #17576: Partial Functions (procs, lambdas) https://bugs.ruby-lang.org/issues/17576#change-99662 * Author: temabolshakov (Tema Bolshakov) * Status: Open * Priority: Normal ---------------------------------------- We already have pattern matching and functions. Let's combine them and introduce a "partial procs" as first-class citizens. What are partial procs? This is a function that works on a subset of arguments. The partial proc's main advantage is that a caller may decide in advance if this proc can accept an argument or not and do something different rather than calling it. That's how it may look like: ```ruby partial_proc = proc do |arg| in x if x.odd? "#{x} is odd" end ``` One can check if a proc is defined on the argument ```ruby partial_proc.defined?(42) #=> false partial_proc.defined?(41) #=> true ``` You can call such a partial proc and it raises an error when it's not defined on this argument: ```ruby partial_proc.call(42) #=> raises NoMatchingPatternError (42) partial_proc.call(41) #=> 41 is odd ``` And finally, we can call or fallback to a default value: ```ruby partial_proc.call_or_else(42) { "fallback value" } #=> 'fallback value' partial_proc.call_or_else(41) { "fallback value" } #=> 41 is odd ``` -- https://bugs.ruby-lang.org/ Unsubscribe: