Haskell嵌套循环累加器

Tim*_*ard 0 haskell loops functional-programming accumulator

我正在努力将我的服务器端编程语言从PHP修改为Haskell,因此我并不完全熟悉函数式语言设计.

在这里,我想将以下php函数的部分处理代码转换为Haskell:

function loop($A) {
  $array1 = array();
  $num = (int)$A;
  if ($num == 0)
    $array1 = "0";
  for (int $i=0; $i<$num; $i++)
    foreach (loop($i-$num) as &$value)
      $array1[] = "+ ".$value." ";  //concat
  return $array1;
}
Run Code Online (Sandbox Code Playgroud)

我想会有大量使用map/mapM_函数,但积累如何工作?我开始认为增加的安全性在这一点上不值得改造.

谢谢.

And*_*ewC 6

这是我正在回答的时候的PHP:

function loop($A) {
  $array1 = array();
  $num = (int)$A;
  if ($num == 0)
    $array1 = "0";
  for (int $i=0; $i<$num; $i++)
    foreach (loop($i-$num) as &$value)
      $array1[] = "+ ".$value." ";  //concat
  return $array1;
}
Run Code Online (Sandbox Code Playgroud)

上述代码到Haskell的字面翻译将是:

loop :: Int -> [String]
loop 0 = ["0"]
loop num = ["+ " ++ value ++ " " | i <- [0..num], value <- loop (i - num)]
Run Code Online (Sandbox Code Playgroud)

它仍然没有实现任何东西,但它确实为你提供了Haskell在列表推导中的"循环"或迭代的味道.

首先要注意的是类型签名loop :: Int -> [String]立即提醒我写,loop 0 = ["0"]而不是loop 0 = "0"更多的字面意思,但是Haskell发现如果有时候是一个字符串列表,有时只是一个字符串,循环的输出会不一致.我认为正是这种错误检查它值得学习 - 也许你在修改时编写的所有代码都会在php中编译,但由于设计不一致,Haskell 不会 - 它会迫使你在写作时清楚地思考并修复bug在编译之前.

我将解释我的代码,不是作为Haskell的完整解释,而是作为一个品尝者并将其与您的代码相关联:

loop :: Int -> [String]
Run Code Online (Sandbox Code Playgroud)

loop是一个函数,它接受一个Integer并返回一个字符串列表.Haskell现在不允许你将它与任何其他数据类型一起使用,这意味着它是类型安全的,并且你可以直接开箱即用,免受各种令人讨厌的错误.类型系统实际上非常灵活,富有表现力和强大,这也是我们喜欢Haskell的原因之一,但在这里我用它来锁定功能.

(列表在Haskell中广泛使用而不是数组.它们非常方便,并且可以快速进行顺序访问.有数组数据类型,但它们不太可爱/ Haskellish - 首先习惯列表.)

loop 0 = ["0"]
Run Code Online (Sandbox Code Playgroud)

这意味着如果loop使用Int 调用0,它应该返回带有一个字符串"0"的列表.

loop num = [ something | stuff... ]
Run Code Online (Sandbox Code Playgroud)

意味着您可以获取变量的值stuff并将其返回something,所以

loop num = [ "+ " ++ value ++ " " | stuff... ]
Run Code Online (Sandbox Code Playgroud)

意味着我们将返回(Haskell的版本)"+ ".$value." ".在这里,我们使用++而不是PHP的..

i <- [0..num]
Run Code Online (Sandbox Code Playgroud)

这意味着让我们i从范围0num.它必须是Int因为num是因为loop :: Int -> ....

value <- loop (i - num)
Run Code Online (Sandbox Code Playgroud)

这意味着value在调用loop数字的范围内调整范围i - num. value必须是String因为loop :: Int -> [String].

在Haskell中,它就像递归调用被实现为表达式重写一样,因此它们在被调用时会消失,并且不会使堆栈混乱,除非您的计算固有地使堆栈混乱.

把它放在一起给出:

loop num = ["+ " ++ value ++ " " | i <- [0..num], value <- loop (i - num)]
Run Code Online (Sandbox Code Playgroud)

如果这种符号感觉非常奇怪,那么你可能会更习惯使用更强制的样式语法:

loop :: Int -> [String]
loop 0 = ["0"]
loop num = do
    i <- [0..num]
    value <- loop (i - num)
    return ("+ " ++ value ++ " ")
Run Code Online (Sandbox Code Playgroud)

当然它仍然没有做任何有用的事情,但至少它很容易跟踪.

为什么不通过http://learnyouahaskell.com/或者真实世界Haskellhttp://book.realworldhaskell.org/上学习一下Haskell for Great Good,这两个教程从简单但深入开始.我想你会发现Haskell是编写少量正确代码以替换大量OK代码的好方法.想得更清楚,少写!