为什么这个功能不会立即失败?

时间:2015-03-10 02:24:02

标签: haskell monads

我有以下代码。 main获取stdin文本并通过g对其进行排序,然后f打印输出并返回使用{{1}提交的相应ExitCode }。

我的问题是为什么这个程序在使用示例输入运行时,不会在输入第一行(exitWith)后立即终止,但只在读取第二行(test后才会失败)?我希望发生的是test2函数在g返回parse1后立即返回,而不是等到输入第二行。

代码:

Left "left: test"

标准输入流:

import System.Exit
import Control.Monad
import Data.Either

type ErrType = String

parse1 :: String -> Either ErrType Int
parse1 "test" = Left "left: test"
parse1 _ = Left "left"

parse2 :: String -> Either ErrType Char
parse2 s = Right (head s)

g :: String -> Either String String
g str =
  let l1:l2:ls = lines str
  in either (Left . show) (Right . show) $ do
    a <- parse1 l1
    b <- parse2 l2
    return "placeholder"

main = getContents >>= f.g >>= exitWith
  where f (Right s) = putStrLn s >> return ExitSuccess
        f (Left s) = putStrLn s >> return (ExitFailure 1)

1 个答案:

答案 0 :(得分:9)

该行

let l1:l2:ls = lines str

意味着即使只评估l1整个模式l1:l2:ls也需要匹配,这意味着需要进行检查str包含至少两行。使用延迟输入会导致您看到的行为。

您可以使用显式延迟模式修复它,该模式推迟检查第二行:

let l1 : ~(l2:ls) = lines str

或者,因为let中的顶部模式是隐式延迟的,所以你可以将其拆分为:

let l1:ls' = lines str
    l2:ls = ls'