[英]How to properly generate a list of String through list comprehension in Haskell?
[英]Haskell string list through lines
我正在使用lines功能来接受输入并拆分许多变量,然后再将其发送给函数。 请查看运行功能,并告诉我为什么出现以下错误。 似乎应该只将ln中的第一个字符串分配给seq,但出现错误。
ERROR:dishonest.hs:33:11:
Couldn't match expected type `[t]' against inferred type `Char'
In a 'do' expression: seq <- ln !! 0
In the expression:
do ln <- lines s
seq <- ln !! 0
states <- ln !! 1
l1 <- listDouble (ln !! 2)
....
In the definition of `run':
run s = do ln <- lines s
seq <- ln !! 0
states <- ln !! 1
....
code follows...
import Char
maximumInd :: (Double, Double) -> Int
maximumInd (d1,d2) | maximum [d1,d2] == d1 = 1
| maximum [d1,d2] == d2 = 2
scoreFunction :: String -> Int -> [Double] -> [Double] -> Double -> Double -> (Double,Double)
scoreFunction string (-1) l1 l2 t1 t2 = (0.5, 0.5)
scoreFunction string index l1 l2 t1 t2 = ((fst (scoreFunction string (index-1) l1 l2 t1 t2)) * (l1!!num) * (tr (maximumInd (scoreFunction string (index-1) l1 l2 t1 t2))!!1), (snd (scoreFunction string (index-1) l1 l2 t1 t2)) * (l2!!num) * (tr (maximumInd (scoreFunction string (index-1) l1 l2 t1 t2))!!2))
where
num = digitToInt (string!!index)
tr n | n == 1 = l1
| n == 2 = l2
--split is stolen from teh webs http://julipedia.blogspot.com/2006/08/split-function-in-haskell.html
split :: String -> Char -> [String]
split [] delim = [""]
split (c:cs) delim
| c == delim = "" : rest
| otherwise = (c : head rest) : tail rest
where
rest = split cs delim
readDouble :: String -> Double
readDouble s = read s :: Double
listDouble :: String -> [Double]
listDouble s = map readDouble $ split s ' '
run :: String -> String
run s = do
ln <- lines s
seq <- ln!!0
states <- ln!!1
l1 <- listDouble (ln!!2)
l2 <- listDouble (ln!!3)
tr1 <- readDouble (ln!!4)
tr2 <- readDouble (ln!!5)
show maximumInd (scoreFunction seq (length seq) l1 l2 tr1 tr2)
main = do
putStrLn "Please compose a test job for Viterbi."
putStrLn "First line: A sequence with language [1,9]."
putStrLn "Second line: The number of states."
putStrLn "For the next 2 lines: space delimited emission probabilities."
putStrLn "For the 2 lines after that, transmission probabilities."
putStrLn "Then do ./casino < filename "
interact run
首先,让我们看一下编译器是如何解释它的:
run :: String -> String
String
实际上是[Char]
。
run s = do
ln <- lines s
...
要简化很多事情, do
块必须在Monad
“运行”。 这意味着它“返回”类型(Monad t) => ta
。 由于此函数返回[Char]
,因此do
块将返回[Char]
,这意味着Monad
为[]
(如果将[a]
读为[] a
,则会更清楚)。
从我的另一个答案中复制,
在IO monad的do块上,很多事情都简化了,每一行都是:
- 返回“ IO a”类型值的东西; 其中的“ a”类型的值将被丢弃(因此,“ a”通常为“()”)
- 一个<-表达式,它执行相同的操作,但不是丢弃“ a”类型的值,而是为其命名为<-左侧
- 一个let,它只给值命名
这里我们不在IO
Monad上,而是在[]
Monad上。 因此, <-
右边的表达式必须是[a]
。
因此,在do
块的第一行中:
ln <- lines s
这里的类型是[[Char]]
,所以ln
的类型是[Char]
。
在下一行:
seq <- ln!!0
此处ln!!0
类型为Char
,但是由于您位于[]
Monad中,因此期望使用某种列表。 这就是导致编译器错误消息的原因。
解决方案是使用普通的let
块,而不是使用do
表示法:
run :: String -> String
run s = let
ln = lines s
seq = ln!!0
states = ln!!1
l1 = listDouble (ln!!2)
l2 = listDouble (ln!!3)
tr1 = readDouble (ln!!4)
tr2 = readDouble (ln!!5)
in show maximumInd (scoreFunction seq (length seq) l1 l2 tr1 tr2)
我没有编译此块,但是即使它有其他问题,也应该足以使您重新开始。
我不确定这是否正确,但是问题可能出在以下事实上: <-
不是赋值运算符,因为您似乎正在使用它。 它本质上是从monad解包一个值。 但是,我不确定这是否是造成您问题的原因。
请记住,列表是haskell中的monad,定义如下:
instance Monad [] where
m >>= f = concatMap f m
return x = [x]
fail s = []
因此,如果您采用自己的代码,则类似于:
do {ln <- lines "hello, world"; ln!!0}
这等效于以下使用绑定符号的方式:
lines "hello world" >>= (\ln -> ln!!0)
或更简而言之:
lines "hello world" >>= (!!0)
现在,我们可以使用列表monad的定义将其重写为以下内容:
concatMap (!!0) (lines "hello, world")
等效于:
concat $ map (!!0) (lines "hello, world")
“ hello,world”行将返回[“ hello,world”],因此在其上映射(!! 0)将产生字符串“ h”。 它的类型为[Char],但是concat的类型为[[t]]。 字符不匹配[t],因此错误。
尝试使用let或其他方式,而不要使用not表示法。
编辑:
所以我认为这是您想要的,使用let而不是do。
run :: String -> String
run s = let ln = lines s
seq = ln!!0
states = ln!!1
l1 = listDouble (ln!!2)
l2 = listDouble (ln!!3)
tr1 = readDouble (ln!!4)
tr2 = readDouble (ln!!5)
in show $ maximumInd (scoreFunction seq (length seq) l1 l2 tr1 tr2)
是的,我认为mipadi是对的。 do表示法将转换为>> =并返回对列表monad的调用。
run s = do
ln <- lines s
seq <- ln!!0
states <- ln!!1
将获得由lines s
返回的列表,对于seq和状态,ln每次都是该列表的字符串。 因此实际上使用ln !! 0,您将获得该字符串的第一个字符。 但是在<-
的右侧需要一个列表。 这就是我所记得的一切。 自从我用haskell做这些东西以来已经有很多时间了:)
run的类型为String-> String,因此您可能不希望使用do表示法[1]。 我建议您这样做:
添加格式与您期望的文件格式相同的测试值。 就像是:
t = "[1,9]\\n3\\n1.0 1.0 1.0\\n1.0 1.0 1.0\\n1.0\\n1.0"
为您在运行中定义的值添加最高级别的测试值
ln = lines t seq = ln!!0 states = ln!!1 l1 = listDouble (ln!!2) l2 = listDouble (ln!!3) tr1 = readDouble (ln!!4) tr2 = readDouble (ln!!5)
使用scoreFunction的类型签名来指导您构建该函数的参数,然后运行其余部分,最后建立main。
学习使用解释器,例如Hugs,ghci。 了解:r和:t命令。 例如(我正在使用currying给出一些但不是全部的函数参数):
:t scoreFunction
:t scoreFunction ""
:t scoreFunction 3445
您可以使用它来使系统帮助您确定自己是否处在正确的轨道上。 在顶层执行此操作会导致与Prelude.seq函数发生冲突-重命名您的seq,或将您的seq引用为Main.seq。
Haskell因对于初学者而言难以理解的错误消息而臭名昭著,因此我建议您定期回滚到可编译的版本,方法是注释掉当前的实验(这是我在上面的第一步中所做的事情),或者使用编辑器撤消功能。
[1]我说这可能是因为字符串(作为字符列表)是Monad类的实例,但这相当先进
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.