Can I reference a lambda from within itself using Ruby?

后端 未结 4 1143
借酒劲吻你
借酒劲吻你 2020-12-28 16:42

I want to be able to call an anonymous lambda from within itself using Ruby. Consider the following recursive block (returns a factorial). I know I can assign it to a variab

4条回答
  •  一向
    一向 (楼主)
    2020-12-28 17:41

    In addition to KL-7's comment, here's a Y combinator solution:

    lambda { |f|
      lambda { |x| x.call(x) }.call(
      lambda { |x| f.call( lambda { |v| x.call(x).call(v) } ) } )
    }.call(
      lambda { |f|
        lambda { |n| n == 0 ? 1 : n * f.call(n - 1) }
      }
    ).call(5) #=> 120
    

    You would normally split these:

    y = lambda { |f|
      lambda { |x| x.call(x) }.call(
      lambda { |x| f.call( lambda { |v| x.call(x).call(v) } ) } )
    }
    
    fac = y.call(
      lambda { |f| lambda { |n| n == 0 ? 1 : n * f.call(n - 1) } }
    )
    
    fac.call(5) #=> 120
    

    Note that although fac is being assigned, it is not used within the lambda.

    I'd use Ruby's -> syntax and .() instead of .call():

    y = ->(f) {
      ->(x) { x.(x) }.(
      ->(x) { f.(->(v) { x.(x).(v) }) } )
    }
    
    fac = y.(->(f) {
      ->(n) { n == 0 ? 1 : n * f.(n - 1) }
    })
    
    fac.(5) #=> 120
    

    The y invocation can be simplified a bit by using curry:

    y = ->(f) {
      ->(x) { x.(x) }.(
      ->(x) { f.curry.(->(v) { x.(x).(v) }) } )
    }
    
    fac = y.(
      ->(f, n) { n == 0 ? 1 : n * f.(n - 1) }
    )
    
    fac.(5) #=> 120
    

提交回复
热议问题