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_函数,但积累如何工作?我开始认为增加的安全性在这一点上不值得改造.
谢谢.
这是我正在回答的时候的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从范围0到num.它必须是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/或者真实世界Haskell在http://book.realworldhaskell.org/上学习一下Haskell for Great Good,这两个教程从简单但深入开始.我想你会发现Haskell是编写少量正确代码以替换大量OK代码的好方法.想得更清楚,少写!