2017-10-11 92 views
1

我在用Ruby语言探索函数式编程。以下是我的Ruby版本。我已经在各种函数上进行了测试,包括反转,过滤器,地图等,并且如预期的那样返回结果。但它会改变数据并需要赋值语句。任何人都可以帮助我做到这一点,但不违反功能范式吗?任何人都可以帮助我在底部部分应用咖喱功能吗?我怀疑有什么明显的我失踪了。谢谢。用Ruby折叠和卷曲

fold_l = lambda do |ray, base, funcky| 
    if ray == [] 
     base 
    else 
     base = funcky.call(base,ray.first) 
     ray.shift 
     fold_l.call(ray,base,funcky) 
    end 
end 

abc = [1, 2, 3, 4, 5, 6, 7] 
mapper = lambda {|sum, x| sum << x*x} 
lengthy = lambda {|sum, _| sum + 1} 

p fold_l.call(abc,[],mapper) ## works fine 
p abc       ## but mutates data!! 
abc = [1, 2, 3, 4, 5, 6, 7] 

p curryFold = fold_l.curry.(abc).(0).(lengthy) ## works fine 
lengthC = curryFold.(base:0).(funcky:lengthy) 
p lengthC.call.(abc) ## but this gives error 

回答

2

返修您fold_l功能,不破坏原参数其给定:

def fold_l(ray, base, funcky) 
    return base if ray.empty? 

    base = funcky.call(base,ray.first) 

    fold_l(ray.last(ray.length-1),base,funcky) 
end 

这使用last返回的参数减去第一个副本。这里也没有必要使用lambda,因为你需要一个命名函数,所以你可以正式声明它。 lambda仅适用于您不一定具有该名称的情况。

请注意,在Ruby中,通常不会损坏您的方法给出的参数,除非理解它是可接受的。如果需要执行更改,大多数方法都会进行复制。

+0

感谢您使用'last'的帮助,我注意到'base = funcky.call(base,ray.first)'部分可以放入fold_l调用的第二个参数中以避免赋值语句。咖喱仍然是一个问题。遵循您的建议,我现在在BOTH声明中遇到错误... –

+0

如果这解决了您的问题,那么它就是解决原始问题的方法。如果你还有其他问题,那么值得把这个问题作为一个专注于这个特定角度的新问题来解决。 – tadman

+1

这不仅是“破坏论证的粗鲁”(nice words mithing!),而且我的理解是,函数式编程的一个基本原则是代码不能有副作用,例如参数的变异。 –

1

我可能会实现foldl这样 - 在不支持尾调用优化(read more

foldl = -> (f, acc, (x,*xs)) do 
    if x.nil? then 
    acc 
    else 
    foldl.call f, (f.call acc, x), xs 
    end 
end 

add = -> (x,y) do 
    x + y 
end 

length = 
    foldl.curry 
    . (-> (acc,_) { acc + 1 }) 
    . (0) 

data = [ 1, 2, 3, 4, 5 ] 

p foldl.call add, 0, data 
# => 15 

p length.call data 
# => 5 

按@ tadman的建议语言使用递归时,使用普通def/end块总是要小心可能是更好的,但是这只是一个偏好的事情 - 请注意,钻营不再需要这种风格

def foldl f, acc, (x,*xs) 
    if x.nil? then 
    acc 
    else 
    foldl f, (f.call acc, x), xs 
    end 
end 

def add x, y 
    x + y 
end 

def length xs 
    foldl (-> (acc,_) { acc + 1 }), 0, xs 
end 

data = [ 1, 2, 3, 4, 5 ] 

p foldl method(:add), 0, data 
# => 15 

p length data 
# => 5 

+0

感谢您的回答。我喜欢'(x,* xs)'技巧,尽管Ruby语法并没有让它更容易理解。我需要4个嵌套parens在参数中获取一个小样本来运行ie:def sample((x,* xs)) –