2017-10-11 101 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)) –