我刚开始学习 Haskell,但我遇到了困难,因为错误消息非常神秘。特别是,当我运行这个应该打印字符串排列数的代码时,我不理解错误消息,
import Data.List
main::IO()
main = do
str <- getLine
print putStrLn $ length $ nub $ permutations str
Run Code Online (Sandbox Code Playgroud)
我得到的错误信息是
但是,当我在 REPL 中运行它时,我没有收到这样的错误:
print putStrLn $ length $ nub $ permutations str
Run Code Online (Sandbox Code Playgroud)
被 Haskell 解析为
print putStrLn ( length ( nub ( permutations str )))
Run Code Online (Sandbox Code Playgroud)
即它调用print2 个参数,putStrLn和length (nub (permutations str))。
您只想使用一个参数调用它,因此还需要一对括号:
print ( putStrLn ( length ( nub ( permutations str ))))
Run Code Online (Sandbox Code Playgroud)
这可以$通过添加一个 s来实现,如
print $ putStrLn $ length $ nub $ permutations str
Run Code Online (Sandbox Code Playgroud)
这仅解决了代码的语法问题。
当然printwithputStrLn是多余的。putStrLn已经完成了所有输出print会做的事情(甚至在此之后再输出一个换行符)。
另一方面putStrLn需要一个字符串,但length产生一个整数。要将其转换为字符串,show可以使用该函数,该函数在print内部自行调用。
所以要么
print $ length $ nub $ permutations str
Run Code Online (Sandbox Code Playgroud)
或者
putStrLn $ show $ length $ nub $ permutations str
Run Code Online (Sandbox Code Playgroud)
从 GHCi 中可以看出:
> :t print . length . nub . permutations
:: Eq a => [a] -> IO ()
> :t putStrLn . show . length . nub . permutations
:: Eq a => [a] -> IO ()
Run Code Online (Sandbox Code Playgroud)
如果有型,它使某些意义上说,至少。
putStrLn接受一个类型String为的参数,正如其签名所证明的那样。
length返回Int,正如其签名所证明的那样。
很明显,尝试将结果length作为参数传递putStrLn会导致类型不匹配。Int不匹配String。就如此容易。
print另一方面,function接受任何类型的参数(请参阅签名),只要该类型有一个Show实例,就Int可以。所以你可以替换putStrLn为print:
print $ length $ nub $ permutations str
Run Code Online (Sandbox Code Playgroud)