OCaml代码:
for x = 0 to 12 do
let i = (1 + (x * 3)) in
let j = (60 - (x * 5)) in
Printf.printf "I=%d J=%d\n" (i) (j);
done;;
我把它翻译成Haskell,但它不起作用:
import Text.Printf
for list action = mapM_ action list
main :: IO ()
main = do
for [0..12] $ \x -> do
let i = (1 + (x * 3))
j = (60 - (x * 5)) in
printf "I=%d J=%d\n" i j :: IO ()
第一个错误是:
从算术序列“0. 12“阻止求解约束”(Enum t0)“。
所以我必须将循环中的代码移动到一个新的函数中,然后它就可以工作了:
import Text.Printf
for list action = mapM_ action list
block :: Int -> IO ()
block x =
let i = 1 + (x * 3)
j = 60 - (x * 5) in
printf "I=%d J=%d\n" i j :: IO ()
main :: IO ()
main = do
for [0..12] $ \x -> do block x
所以我的问题是Haskell允许在内部作用域中声明变量吗?如果是的话,我错过了什么?
在replit.com上测试
1条答案
按热度按时间2nbm6dog1#
在这个片段中:
这里没有明确指出使用的是哪种数值类型。这将检查是否为
0
,12
等。是Int
s,Integer
s,Word64
s,Double
s或Complex
。在某些有限的情况下,GHC会将未知的数值类型“默认”为
Integer
或Double
,这取决于它的使用方式,但这依赖于未知类型被约束到一组有限的“内置”类型类,而printf
的使用引入了一个额外的类型类约束,干扰了这个默认过程。如果避免使用printf
,则默认类型将按预期工作,因此以下工作(数字类型默认为Integer
):或者,如果你添加一个类型签名来显式地指示你想要使用的数值类型,它也可以工作:
你也可以在
let
语句中给予类型签名,所以这也可以工作:基本上,任何让GHC找出类型的东西都会修复这个错误。您使用
block
的版本能够正常工作的原因是block
具有将数值类型确定为Int
的类型签名。如果你忽略了这个类型签名,你会得到同样的错误: