我还在学习haskell,我发现了一个使用以下hangman简单程序介绍IO概念的教程
import System.IO
import System.Random
main = do
handle <- openFile "enable1.txt" ReadMode
contents <- hGetContents handle
gen <- getStdGen
let words = map init (lines contents)
(n, _) = randomR(0, (length words) - 1) gen :: (Int, StdGen)
word = words !! n
play word (map (\x -> '_') word) 6
build the print the string
hClose handle
play word known guesses
| word == known = do
putStrLn known
putStrLn "You win!!"
| guesses == 0 = do
putStrLn known
putStrLn ("You lose. the word was " ++ word ++ ".")
| otherwise = do
putStrLn known
putStrLn ("You have " ++ guesses ++ "guesses left.")
line <- getLine
let (newKnown, newGuesses) = handle (head line) word known guesses
play word newKnown newGuesses
--putStrLn (handle (head line) word)
handle letter word known guesses
| letter `elem` word = (zipWith (\w k -> if w == letter then w else k) word known, guesses)
| otherwise = (known, guesses - 1)
enable1.txt是一个包含大量单词的本地文件。 我使用runhaskill运行该文件 我收到以下错误:
:~/Documents/atom/haskell$ runhaskell hangman.hs
hangman.hs:22:36: error:
• No instance for (Num [Char]) arising from the literal ‘6’
• In the third argument of ‘play’, namely ‘6’
In a stmt of a 'do' block: play word (map (\ x -> '_') word) 6
In the expression:
do { handle <- openFile "enable1.txt" ReadMode;
contents <- hGetContents handle;
gen <- getStdGen;
let words = map init (lines contents)
(n, _) = ...
....;
.... }
hangman.hs:30:16: error:
• No instance for (Num [Char]) arising from the literal ‘0’
• In the second argument of ‘(==)’, namely ‘0’
In the expression: guesses == 0
In a stmt of a pattern guard for
an equation for ‘play’:
guesses == 0
hangman.hs:37:36: error:
• No instance for (Num [Char]) arising from a use of ‘handle’
• In the expression: handle (head line) word known guesses
In a pattern binding:
(newKnown, newGuesses) = handle (head line) word known guesses
In the expression:
do { putStrLn known;
putStrLn ("You have " ++ guesses ++ "guesses left.");
line <- getLine;
let (newKnown, newGuesses) = handle (head line) word known guesses;
.... }
任何人都可以帮助我了解问题/如何解决它。 runhaskell --version是runghc 8.0.2
答案 0 :(得分:3)
其他人已经在您的代码中指出了一些问题。在这里,我只想为您提供一般性建议。
大多数Haskellers,包括&#34; expert&#34;,总是从类型注释开始编写任何新的顶级函数(或一般的绑定)。也就是说,写foo :: Type1 -> Type2 -> ... -> ReturnType
。实际上,强烈建议这有几个原因。
首先,它有助于程序员专注于他们必须处理或生成的数据类型。对于简单的程序来说,这在程序员的脑海中可能是显而易见的,但在更严肃的高级代码中它变得不那么重要。
其次,它阻止类型推理引擎推断出非预期的类型。例如,请考虑此代码。
foo x = "hello" ++ x -- line A
这可以毫无问题地被接受,并且x
被GHC推断为String
类型。
然而,在程序员的心中x
应该是一个整数,所以,稍后,程序员会写
let s = foo 42 in ... -- line B
并且GHC抱怨42
不是String
。或者更糟糕的是,Num String
无法满足,这意味着字符串不是数字类型。现在程序员很困惑,因为GHC指向B行作为问题,但该代码对程序员来说很好。 &#34;我传递一个整数,foo
需要一个整数,这个奇怪的字符串错误来自哪里?!?&#34;
这不是编译器的错 - 它无法知道A行中的代码是错误的。但是,如果程序员告诉编译器,在A行附近,x
本来是一个整数,那么它确实是编译器的错误!编译器现在应该抱怨A行中的错误!事实上,确实如此:这是一个GHCi快速测试。
> foo :: Int -> String ; foo x = "hello" ++ x
error:
• Couldn't match expected type ‘[Char]’ with actual type ‘Int’
• In the second argument of ‘(++)’, namely ‘x’
In the expression: "hello" ++ x
In an equation for ‘foo’: foo x = "hello" ++ x
阿公顷! ++
需要一个字符串,但x
是一个整数。所以我们必须转换它
> foo :: Int -> String ; foo x = "hello" ++ show x
现在,没有错误发生。
一般来说,当编码并犯一些错误时,可能会导致GHC推断出非预期的类型,导致后来出现令人费解的错误,指向看似完美的代码。在这种情况下,常见的技术是添加越来越多的类型注释,通知编译器程序员的意图,以便GHC可以产生更有意义的错误。最终,GHC和程序员都认为出了问题,而且可以修复bug。
答案 1 :(得分:2)
您收到错误,因为程序中的类型不一致。
X
表示“[Char]
不是任何数字”。String
是字符串的类型(play
是其别名)。查看您的代码,我可以在"You have " ++ guesses ++ "guesses left."
中看到
guesses
表示guesses == 0
必须是字符串,才能与其他字符串连接。guesses
表示show
必须是数字。如果您从教程中获得了此代码,那么这是一个编写得很糟糕的教程,您应该找到一个更好的教程。如果您是根据教程自己编写的,那么您一定错过了一步。
为了将数字转换为字符串进行打印,您可以使用"You have " ++ show guesses ++ "guesses left."
函数:
{{1}}
答案 2 :(得分:1)
您不能(++)
String
和数字类型。您应首先使用函数show
将数字转换为String
,然后才能将其与另一个字符串连接。
在您的代码中,参数word
和known
属于某种类型Num a => a
,但(++)
只接受两个String
(即[Char]
)作为参数(准确地说,它接受两个相同类型元素的列表,并且因为您已经应用了String
,所以另一个参数也应该是String
)。因此,您应将word
替换为show word
,将known
替换为<div style="height: 300px;"
leaflet
[leafletOptions]="options">
</div>
。