如何 return 一个函数根据输入调用另一个函数?

How to return a function calling another function based on the input?

我对 Haskell 真的很陌生,我需要 return 一个 "has modified" 输入函数的函数。

我猜你不能复制和修改原始函数(基于某些条件)所以你必须直接实现自己的行为然后调用原始函数?

这是我的方法:

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 得到的错误是

haskell/eggcartons.hs:42:54: parse error on input ‘where’

指向第一个where之后的第一个词。

(供参考:我也尝试在这里设置更多括号http://pastebin.com/2wTqAqpm and I tried doing it with guards http://pastebin.com/RVm28Y7n, but that's only making it worse without thouroughly understanding that? At least guards worked for me here http://pastebin.com/uQeFwLU5

我在 Haskell 中搜索了 returning 函数,但我只得到了一些随机信息,这些信息用于我所做的 where 事情。

我的想法对吗?这只是一个小错误吗?

对于进一步阅读有关 returning 函数语法的任何帮助,我们也非常感谢!

看看这是否符合您的要求:

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 子句)。

首先让我们让它更易读...

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 的这些定义之一之后使用 where。但是你不能把它放在代码中间的任何地方,比如 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 仅在定义后立即使用一次,则实际上不需要用名称定义它。这是 lambdas 的明确应用:

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

我们有 ifs 紧跟在模式匹配之后。这现在非常适合 guards:

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