无法在Haskell中将`Char'与`[Char]'匹配?

时间:2017-03-17 18:47:23

标签: haskell

我可以问为什么我会这样吗?

无法匹配类型Char' with [Char]'

预期类型:[String]

实际类型:[Char]

(:)', namely开始'

的第二个参数中

在表达式中:( show gm:start)

main :: IO ()
main = do
    c <- parseArguments <$> getArgs
    input <- hGetContents stdin
    either print (handleGM input) c

handleGM input Config{..} = do
    handleGM <$> readFile tgrammer >>= either putStrLn (mapM_ putStrLn)
  where
    handleGM gm = do
        gm' <- parseGM gm
        case action of
             Simulate -> printGrammer gm' input

printGrammer gm@TGrammer{..} input =
    (show gm:start)

数据:

type TState = String
type TSymbol = Char

data TGrammer = TGrammer
   { neterminaly :: [TState]
   , terminaly :: [TState]
   , start :: [Char]
   , rules :: [Rules]
   }
  deriving (Show)

data Rules = Rules
    { from :: TSymbol
    , to :: String
    }
   deriving (Show)

1 个答案:

答案 0 :(得分:1)

有很多事情对你的代码很奇怪,所以希望纠正它们可以帮助你解决问题。

类型签名

您应始终在顶级绑定中包含类型签名,以及任何非平凡的wherelet绑定。这些是我对你想要的类型的最佳猜测:

handleGM :: String -> Config -> IO ()
printGrammer :: TGrammer -> String -> IO ()

阴影绑定

handleGM似乎被定义了两次,一次在where绑定中。这是非常糟糕的练习,因为它看起来像是在尝试进行递归调用。您应该考虑重命名内部函数,或者在这种情况下,只需将其写入do-notation,因为它不是递归的(因此不需要where绑定)。事实上,你误用了<$>,它只能用于将纯函数映射到不纯的值上。在这种情况下,您尝试使用它来映射不纯值的不纯函数,这会导致混淆而不是您想要选择Either String ()作为内部handleGM的类型}。

操作员过度使用

如果你的代码不能正常工作,最好不要使用<$>>>=,因为它可以隐藏实际发生的事情,所以当你遇到问题时明确写出来(do-notation)像这样。

以下是基于以上内容修改handleGM的方法:

handleGM :: String -> Config -> IO ()
handleGM input Config{..} = do
  a <- readFile tgrammer
  b <- either putStrLn (mapM_ putStrLn) a
  gm' <- parseGM b
  case action of
    Simulate -> printGrammer gm' input

[Char]与Char

不匹配

这是因为你使用了cons运算符(:) :: Char -> [Char] -> [Char],但你给它的第一个参数已经是[Char](即show gm)。您可能想要的是(++) :: [Char] -> [Char] -> [Char],它会将您的两个[Char]组合成一个更长的[Char]。您可能还想打印到终端而不是计算[Char] ,这意味着您需要使用像putStrLn :: String -> IO ()这样的函数。如果这些是准确的,我将修改printGrammer到:

printGrammer :: TGrammer -> String -> IO ()
printGrammer gm@TGrammer{..} input = putStrLn (show gm ++ start)

  • 你似乎没有对input做任何事情,所以为什么还要费心去做呢?
  • 通过在编译时将其作为参数传递来启用-Wall,您可能会受益。它打开所有编译器警告,因此它会告诉您是否可能犯了错误。
  • case只有一个案例。如果它没有做任何不同的事情,为什么要case呢?
  • action似乎是凭空掏出来的;它来自哪里?