我可以问为什么我会这样吗?
无法匹配类型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)
答案 0 :(得分:1)
有很多事情对你的代码很奇怪,所以希望纠正它们可以帮助你解决问题。
您应始终在顶级绑定中包含类型签名,以及任何非平凡的where
或let
绑定。这些是我对你想要的类型的最佳猜测:
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
这是因为你使用了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
似乎是凭空掏出来的;它来自哪里?