2015-04-21 39 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子句)。

相关问题