【问题标题】:Haskell string list through linesHaskell字符串列表通过行
【发布时间】:2010-09-22 13:01:07
【问题描述】:

我正在使用行功能来获取输入并在将其发送到函数之前拆分许多变量。请查看运行函数并告诉我为什么会出现以下错误。似乎它应该只将 ln 中的第一个字符串分配给 seq,但我得到一个错误。

错误:不诚实.hs:33:11: 无法将预期类型“[t]”与推断类型“Char”匹配 在“do”表达式中: seq 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

【问题讨论】:

    标签: string haskell functional-programming


    【解决方案1】:

    首先,让我们看看编译器是如何解释它的:

    run :: String -> String
    

    String 实际上是[Char]

    run s = do
        ln <- lines s
        ...
    

    简化事情很多do 块必须在Monad 中“运行”。这意味着它“返回”一个(Monad t) =&gt; t a 类型的值。由于这个函数返回[Char],所以do块将返回[Char],这意味着Monad[](如果你把[a]读成[] a,会更清楚)。

    复制自我的another answer

    简化了很多事情,在 IO monad 的 do 块上,每一行都是:

    • 返回“IO a”类型值的东西;其中“a”类型的值被丢弃(因此“a”通常为“()”)
    • 一个 的左侧
    • 一个 let,它只是为一个值命名

    我们不是在IO Monad,而是在[] Monad。所以&lt;-右边的表达式必须是[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)
    

    我没有编译这个块,但即使它有其他问题,也应该足以让你重新开始。

    【讨论】:

      【解决方案2】:

      我不确定这是否正确,但问题可能在于&lt;- 不是赋值运算符,正如您似乎正在使用它;它本质上是从一个 monad 中解包一个值。但我不确定这是否是您的问题的原因。

      【讨论】:

        【解决方案3】:

        是的,我认为 mipadi 是对的。 do 表示法转换为 >>= 并返回对列表 monad 的调用。

        run s = do
            ln <- lines s
            seq <- ln!!0
            states <- ln!!1
        

        将获得lines s 返回的列表,对于 seq 和状态,ln 每次都是该列表的字符串。所以实际上使用 ln!!0,你会得到那个字符串的第一个字符。但是在&lt;- 的右侧需要一个列表。这就是我记得的所有内容。自从我用 haskell 做这些事情以来已经有很长一段时间了:)

        【讨论】:

          【解决方案4】:

          请记住,列表是 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)
          

          我们现在可以使用 list monad 的定义将其重写如下:

          concatMap (!!0) (lines "hello, world")
          

          相当于:

          concat $ map (!!0) (lines "hello, world")
          

          行 "hello, world" 将返回 ["hello, world"],因此在其上映射 (!!0) 将生成字符串 "h"。它具有类型 [Char],但 concat 需要类型 [[t]]。 Char 与 [t] 不匹配,因此出现错误。

          尝试使用 let 或其他东西而不是 do 表示法。

          编辑:

          所以我认为这就是你想要的,使用 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)
          

          【讨论】:

          • 感谢您刷新我的记忆,了解如何将 do 翻译成 monad 想要的内容。你能指出 let 的东西是如何翻译的吗?我认为这对他和我也有帮助:)
          • 我认为在 do 表示法中使用 let 只是转换为 let ..... in do .... 。我稍微记得
          • 我不认为让表达式实际上可以翻译成任何更原始的形式(我可能错了),它只是一种基本的语言结构。我更新了我的帖子以显示我认为 OP 想要什么。
          【解决方案5】:

          run 是 String -> String 类型,因此您可能不需要 do 表示法[1]。我建议你这样做:

          1. 注释掉下面的所有内容 listDouble 函数,加载它,然后 确保会编译。
          2. 添加一个格式与您期望的文件类似的测试值。比如:

             t = "[1,9]\n3\n1.0 1.0 1.0\n1.0 1.0 1.0\n1.0\n1.0"  
            
          3. 为您在运行中定义的值添加顶层测试值

            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)   
            
          4. 使用的类型签名 scoreFunction 为您提供指导 建立论据 函数,然后是运行的其余部分,最后是 main。

          学习使用解释器,例如 Hugs、ghci。学习 :r 和 :t 命令。例如(我使用柯里化来给出一些但不是全部的函数参数):

            :t scoreFunction
            :t scoreFunction ""
            :t scoreFunction 3445
          

          您可以使用它让系统帮助您确定您是否走在正确的轨道上。 在顶层执行此操作会引入与 Prelude.seq 函数的冲突 - 重命名您的 seq,或将您的引用为 Main.seq。

          Haskell 因初学者难以理解的错误消息而臭名昭著,因此我建议定期回滚到可编译的版本,或者通过注释掉您当前的实验(这是我在上面的步骤 1 中让您做的),或使用您的编辑器撤消功能。

          [1]我说可能是因为作为字符列表的字符串是 Monad 类的实例,但这是相当先进的

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-05-18
            • 1970-01-01
            • 2020-01-05
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多