我的程序有问题:程序必须逐行读取文件,并且必须说它是否是一个palindrom和每个单词的长度。我在Haskell中非常新,只有这个,但它不起作用:(
main = do
inhalt <- readFile "palindrom.txt"
laengeWort = length inhalt
if istPalindrom inhalt
then putStrLn (inhalt ++ " ist ein Palindrom und hat die Laenge "++ laengeWort
else putStrLn (inhalt ++" ist kein Palindrom und hat die Laenge " ++ laengeWort)
isPalindrom w = w == reverse w
请帮我正确完成我的程序:)
答案 0 :(得分:2)
首先,在do块中,在引入变量时,您应该使用 let
关键字。 (或者在提取monad的值时使用<-
,就像读取文件时一样。)
laengeWort = length inhalt
变为
let laengeWort = length inhalt
其次,laengeWort
变量的类型为Int
,您需要使用show
函数将其转换为String。 (Haskell并没有像其他语言那样将类型隐式转换为String。)
最后,您错误地将isPalindrom
误认为istPalindrome
而你忘了从then putStrLn (
开始关闭parens
语法上正确的解决方案是(我把它翻译成英文):
main = do
contents <- readFile "palindrom.txt"
let contentLength = length contents
if isPalindrome contents then
putStrLn (contents ++ " is a palindrome of length "++ show contentLength)
else
putStrLn (contents ++" is not a palindrome, it has the length " ++ show contentLength)
此外,此解决方案对整个文件进行操作,就像是单个字符串/单词一样。从您的描述中可以看出,您希望将每一行视为一个不同的词。为此,请使用lines
函数按行分割内容,并使用partition
将单词过滤为回文单词和非单词。然后,您可以使用mapM_
打印每个单词。这是一个相当简洁的例子(尽管它没有保留单词的顺序):
import Data.List (partition)
main = do
contents <- lines `fmap` readFile "palindrom.txt"
let (palins,notPalins) = partition isPalindrome contents
mapM_ (\w -> putStrLn $ "the word " ++ w ++ " is a palindrome of length " ++ show (length w)) palins
mapM_ (\w -> putStrLn $ "the word " ++ w ++ " is not a palindrome, it has length" ++ show (length w)) notPalins
isPalindrome w = w == reverse w
我使用了&#39; fmap&#39;将lines函数(采用纯字符串)映射到 readFile(在IO monad中返回一个字符串)的结果,得到IO monad中的字符串列表,以及&#39;&lt; - &#39;运算符从monad中提取该列表。 这相当于说:
rawData <- readFile "palindrom.txt"
let contents = lines rawData
答案 1 :(得分:2)
问题是您正在使用readFile
,它会将"palindrom.txt"
的全部内容读入单个String
。您需要将文件的内容拆分为行,然后将isPalindrom
应用于行。您可以使用lines
内置函数执行此操作,然后使用mapM_
。为了使其更清晰,您可以使用forM_
中的Control.Monad
,mapM_
只更换参数顺序:
mapM_ :: Monad m => (a -> m b) -> [a] -> m ()
forM_ :: Monad m => [a] -> (a -> m b) -> m ()
我大多数时候都喜欢它,因为它看起来更像是来自其他语言的for循环。所以你的代码看起来像
import Control.Monad (forM_)
main = do
inhalt <- readFile "palindrom.txt"
forM_ (lines inhalt) (\wort -> do
let laengeWort = length wort
putStrLn (if istPalindrom wort
then wort ++ " ist ein Palindrom und hat die Laenge " ++ show laengeWort
else wort ++ " ist kein Palindrom und hat die Laenge " ++ show laengeWort
)
)
istPalindrom w = w == reverse w
我还将putStrLn
提升到if
语句之前,使其更清洁,并使线条更短。
你在语法方面遇到了一些问题,但是当你是初学者并且大部分教程都没有用你的母语时,这是非常可原谅的。
为了清理这些代码,我可能会将消息格式化为另一个函数:
macheNachricht :: String -> String
macheNachricht wort =
let nachricht = if istPalindrom wort
then " ist ein Palindrom"
else " ist kein Palindrom"
laengeWort = show (length wort)
in wort ++ nachricht ++ " und hat die Laenge " ++ laengeWort
然后main
看起来像
main = do
inhalt <- readFile "palindrom.txt"
forM_ (lines inhalt) (\wort -> putStrLn (macheNachrict wort))
这可以使用Haskell的函数组合运算符.
进一步减少,该运算符被定义为
f . g = \x -> f (g x)
由于这正是\wort -> putStrLn (macheNachricht wort)
作为forM_
的第二个参数所具有的,我们可以将其写为putStrLn . macheNachricht
:
main = do
inhalt <- readFile "palindrom.txt"
forM_ (lines inhalt) (putStrLn . macheNachricht)
(对不起,如果makeMessage
将macheNachricht
翻译为德语{{1}}有点不精确,我自己就开始学习德语,而且我还不是很好。)< / p>