【问题标题】:Is there an equivalent to F# |> (method chaining) in Ruby?Ruby 中是否有等效于 F# |> (方法链接)的方法?
【发布时间】:2013-10-12 22:55:33
【问题描述】:

我在 F# 中有一个例子:

let a n = Convert.ToString(n:int32)

我可以说:

3 |> a

计算结果为"3"。 Ruby 中有类似的构造吗?

这是 F#(和其他 FP 语言)的方法链接,它不是函数组合,也不是 Ruby 中的方法链接,即返回 self 的对象,以便可以像 @987654324 中那样调用对象上的其他方法@。

【问题讨论】:

  • FFR:如果您只想将 3 整数转换为字符串 "3",那么 Ruby 让您只需执行 3.to_s

标签: ruby f# chaining


【解决方案1】:

这在 Ruby 中很容易实现。直接取自 F# 参考文档:

let function1 x = x + 1
let function2 x = x * 2

let result = 100 |> function1 |> function2
//> val result : int = 202

这可以用 Ruby 编写如下:

function1 = -> x { x + 1 }
function2 = -> x { x * 2 }

result = 100.pipe(function1).pipe(function2)
# => 202

使用Object#pipe的以下实现:

class Object
  def pipe(callable)
    callable.(self)
  end
end

或者用你的例子:

a = -> n { String(n) }

3.pipe(a)
# => '3'

还有

let f x y = x * y

3 |> f(2)
// > 6

变成

f = -> (x, y) { x * y }

3.pipe(f.curry.(2))
# => 6

【讨论】:

  • Ruby 是否支持部分应用程序?如果您不必独立声明单个参数函数,则管道最有用...
  • 当你需要函数柯里化行为时,事情会变得更加复杂,这在 F# 中是可能的,但在 ruby​​ 中需要一个全新的 DSL。例如。 let f x y = x * y 然后3 |> f(2)
  • @IgorS.: f = -> (x, y) { x * y }; 3.pipe(f.curry.(2))
  • 虽然它仍然是一个 DSL,但您的解决方案是一个非常酷的 OSS 项目的开始。感谢您在此处发布
  • @JörgWMittag 感谢 Jörg 的出色回答。我在article on the Code Project 中发布了关于流水线和组合的完整讨论
【解决方案2】:

Ruby 不支持这种 F#/Ocaml/Haskel 表示法。虽然我相信你可以做点什么。但关键是你不应该这样做。

如果你想以函数式风格实现事物(这很棒),你可以使用 ruby​​ 提供的 Enumerable 功能 - injectmapselect 等。

这将产生一个干净可读的 ruby​​ 代码,没有 hack。

PS:+1 的问题。刚开始使用 ruby​​ 时,我自己也问过。

【讨论】:

    【解决方案3】:

    没有这样的表示法,但您可以向Object 添加一个方法,将self 传递给给定的方法。比如:

    class Object
      def pass_to(m)
        m.call(self)
      end
    end
    

    这将允许这样的调用:

    def convert_to_string(n)
      n.to_s
    end
    
    def reverse_string(s)
      s.reverse
    end
    
    123
      .pass_to(method(:convert_to_string))
      .pass_to(method(:reverse_string))
    #=> "321"
    

    或者使用 lamdas:

    convert_to_string = -> n { n.to_s }
    reverse_string = -> s { s.reverse }
    
    123
      .pass_to(convert_to_string)
      .pass_to(reverse_string)
    #=> "321"
    

    这相当于将to_s消息发送给123(返回"123"),然后将reverse消息发送给"123"

    123
      .to_s
      .reverse
    #=> "321"
    

    【讨论】:

    • 您可以在 pass_to 和 Object#pass_to 中将方法作为符号传递:m = method(:m)。认为这种方式可能更具可读性(而不是一直重复“方法”作为 pass_to 的参数。
    猜你喜欢
    • 2015-09-08
    • 2010-12-11
    • 2019-09-12
    • 2011-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-19
    • 2018-07-06
    相关资源
    最近更新 更多