2015-04-21 71 views
1

對於Haskell,我真的很新,我需要返回一個「已修改」輸入函數的函數。如何根據輸入返回調用另一個函數的函數?

我想你不能複製和修改原始函數(基於某些條件),所以你必須直接實現自己的行爲,然後調用原始函數?

這是我的方法:

switchFirstEgg eggCarton = if eggCarton 1 == 0 
           then switchedCarton where switchedCarton position = if position == 1 then 2 else eggCarton position 
           else if eggCarton 1 == 1 
             then switchedCarton where switchedCarton position = if position == 1 then 0 else eggCarton position 
             else if eggCarton 1 == 2 
               then switchedCarton where switchedCarton position = if position == 1 then 1 else eggCarton position 
               else switchedCarton where switchedCarton position = eggCarton position 

我從GHCI得到的錯誤是

哈斯克爾/ eggcartons.hs:42:54:輸入解析錯誤 '其中'

哪個指向第一個字之後的第一個字where

(參考:我也想在這裏設置多個支架http://pastebin.com/2wTqAqpm,我試圖與警衛http://pastebin.com/RVm28Y7n這樣做,但這只是使事情變得更糟而不會操作裝配理解,至少警衛工作對我來說這裏http://pastebin.com/uQeFwLU5?)

我搜索了Haskell中的函數,但我只有幾個隨機信息,我使用了我所做的where事情。

我的理念對嗎?這只是一個小錯誤嗎?

任何幫助進一步閱讀有關返回函數的語法也非常感謝!

回答

6

首先讓我們把這個有點可讀......

switchFirstEgg ec 
    = if ec 1 == 0 
     then sc where sc pos = if pos == 1 
           then 2 
           else ec pos 
     else if ec 1 == 1 
       then sc where sc pos = if pos == 1 
             then 0 
             else ec pos 
       else if ec 1 == 2 
        then sc where sc pos = if position == 1 
              then 1 
              else ec pos 
        else sc where sc pos = ec pos 

現在。 where只能按照的定義使用一次,即在您編寫switchFirstEgg _ = ...後,您可以按照where,該值對=之後的所有值都有效。或者,您可以在本地更多地使用sc的其中一個定義之後的地方。但是你不能將它粘在代碼中間的任何地方,比如在if分支中。

非常相似let結構確實允許這一點,所以你嘗試一下最簡單的翻譯是

switchFirstEgg ec 
    = if ec 1 == 0 
     then let sc pos = if pos == 1 then 2 
             else ec pos 
      in sc 
     else if ec 1 == 1 
       then let sc pos = if pos == 1 then 0 
              else ec pos 
        in sc 
       else if ec 1 == 2 
        then let sc pos = if pos == 1 then 1 
                else ec pos 
         in sc 
        else let sc pos = ec pos 
         in sc 

但這是笨重。如果在定義之後立即使用一次,則不需要使用名稱來定義sc。這對lambda表達式一個明確的應用程序:

switchFirstEgg ec 
    = if ec 1 == 0 
     then \pos -> if pos == 1 then 2 
           else ec pos 
     else if ec 1 == 1 
       then \pos -> if pos == 1 then 0 
             else ec pos 
       else if ec 1 == 2 
        then \pos -> if pos == 1 then 1 
              else ec pos 
        else \pos -> ec pos 

更好,但是這條產業鏈的if顯然是更好的表述爲case條款單個集合。

switchFirstEgg ec = case ec 1 of 
    0 -> \pos -> if pos == 1 then 2 
           else ec pos 
    1 -> \pos -> if pos == 1 then 0 
           else ec pos 
    2 -> \pos -> if pos == 1 then 1 
           else ec pos 
    _ -> \pos -> ec pos 

在這一點上變得清晰,pos綁定是相當一致的,所以我們就可以移動它們都一個級別:

switchFirstEgg ec pos = case ec 1 of 
    0 -> if pos == 1 then 2 
         else ec pos 
    1 -> if pos == 1 then 0 
         else ec pos 
    2 -> if pos == 1 then 1 
         else ec pos 
    _ -> ec pos 

在那裏,我們有if小號緊隨其後的模式相匹配。這是現在的後衛一個完美契合:

switchFirstEgg ec pos = case ec 1 of 
    0 | pos == 1 -> 2 
    1 | pos == 1 -> 0 
    2 | pos == 1 -> 1 
    _ -> ec pos 

或者,你可以馬上匹配pos,之前甚至考慮ec 1

switchFirstEgg ec 1 = case ec 1 of 
    0 -> 2 
    1 -> 0 
    2 -> 1 
    n -> n 
switchFirstEgg ec pos = ec pos 
+1

我不同意用'ec'更換'eggCarton'和'sc'的'switchedCarton'有助於提高可讀性。否則,這是一個很好的答案。 – WolfeFan

+1

@WolfeFan:好吧,在這種情況下,原始版本很難閱讀,因爲它的寬度很寬。將變量縮寫爲兩個字母當然不總是一個好主意,但是任何經常出現八次的名字都應該保持較短(或者至少在本地被別名爲短)。 – leftaroundabout

+1

很好的答案。請注意,如果'pos'爲'1'且'ec 1'爲'3',最後一個答案將會崩潰,這與以前的替代方法不同,因爲這種情況並非詳盡無遺。當然,可以在案件中添加'_ - > ec pos'來防止這種情況發生。 – chi

3

看看這個你想要做什麼:

switchFirstEgg eggCarton = 
    switchedCarton 
    where switchedCarton = case (eggCarton 1) of 
         0 -> \position -> if position == 1 
              then 2 
              else eggCarton position 
         1 -> \position -> if position == 1 
              then 0 
              else eggCarton position 
         2 -> \position -> if position == 1 
              then 1 
              else eggCarton position 
         _ -> \position -> eggCarton position 

只能有一個函數定義一個where條款(儘管內where條款函數定義可以有自己的where子句)。

相關問題