提问人:Alejandro Caro 提问时间:9/11/2023 最后编辑:Alejandro Caro 更新时间:9/12/2023 访问量:115
在 Haskell 中为 块 (for block) 进行分配
Assignment in Haskell within for block
问:
我正在尝试制作一个函数来计算一个数字的阶乘。它在作业中标记了一个错误,我不知道如何更正它。
for list action = mapM_ action list
main :: IO Int
main = do
x <- getLine
for [1..read x] (\ i -> do
let tmp = 0
tmp <- tmp*i
)
return (tmp)
答:
首先,关于循环的说明。我假设for_
。Haskell没有任何循环关键字,但它的monad范式足够灵活,因此它们可以作为库函数实现。
但是,Haskell 没有可变变量。所以这样的事情永远没有意义。
(注意,你实际上可以写,但不要这样做。它没有任何用处;它没有更新变量,而是定义了一个变量,但用一个无意义的循环定义来引用它自己的结果,即这只是一个非终止计算。tmp <- tmp*i
let tmp = tmp*i
好吧,关于没有可变变量的说法并不完全正确。这些也可以从标准库中获得,它们称为 IORef
s。但是,它们不能使用语法或语法进行更新,而是使用模块中定义的操作进行更新。以下方法确实有效:<-
=
IO
Data.IORef
import Data.Foldable (for_)
import Data.IORef
main :: IO ()
main = do
x <- getLine
tmp <- newIORef 1
for_ [1 .. read x] (\ i -> do
modifyIORef tmp (*i)
)
readIORef tmp
请注意,没有 .在 Haskell 中,return
不是一个关键字(注意到一个主题?),而只是一个将纯值(在本例中为 )注入到单子动作中的函数(在本例中为 )。但是阅读本身已经是一个不纯粹的动作,因此你应该简单地用它作为最后一行。return
Int
IO Int
IORef
不过,返回值可能不是您想要的(返回值被忽略);我想你是想打印它:main
import Data.Foldable (for_)
import Data.IORef
main :: IO ()
main = do
x <- getLine
tmp <- newIORef 1
for_ [1 .. read x] (\ i -> do
modifyIORef tmp (*i)
)
result <- readIORef tmp
print result
好了,这就是你问题的字面修复。
但是,强烈建议不要用于此类操作。一般来说,Haskell的整个理念是避免突变等副作用。相反,您应该通过递归来定义函数,并且仅在最后用于打印完整结果。这方面的例子数不胜数,一个幽默的例子是 Haskell 程序员的演变。IORef
IO
评论
Control.Monad.forM_
,但 chi 指出现在更喜欢Data.Foldable.for_
。当然,进口需要相应调整。
for_
forM_
Haskell是一种函数式语言。如果这种语言的方面是变量是不可变的:一旦分配了一个值,你就永远无法改变该值。
因此,Haskell没有内置循环等。它的“主力”是递归:我们递归,直到确定某个值。对于阶乘情况,如下所示:for
factorial :: Int -> Int
factorial 0 = 1
factorial n = …
然后主要可以如下所示:
main :: IO ()
main = do
n <- readLn
print (factorial n)
或更短:
main :: IO ()
main = readLn >>= print . factorial
评论
for
main = do x <- getLine; print (factorial (read x))
for
tmp