以下代码不起作用:
gcd' :: Int -> Int -> Writer String Int
gcd' a b
| b == 0 = do
tell "gcd " ++ show a ++ " " ++ show b ++ " \n"
return a
| otherwise = do
tell "gcd " ++ show a ++ " " ++ show b ++ " \n"
gcd' b (a `mod` b)
当我将代码更改为此时,它现在可以工作:
gcd' :: Int -> Int -> Writer [String] Int
gcd' a b
| b == 0 = do
tell ["gcd " ++ show a ++ " " ++ show b ++ " \n"]
return a
| otherwise = do
tell ["gcd " ++ show a ++ " " ++ show b ++ " \n"]
gcd' b (a `mod` b)
尽管我现在必须串联字符串列表。
我不明白为什么我的原始代码不起作用。当然,我的原始代码应将每个步骤中的字符串连接起来,以提供总体日志。但是,相反,它给了我以下错误消息:
gcdLogger.hs:6:6: error:
• Couldn't match type ‘[]’
with ‘WriterT String Data.Functor.Identity.Identity’
Expected type: WriterT String Data.Functor.Identity.Identity ()
Actual type: [()]
• In a stmt of a 'do' block:
tell "gcd " ++ show a ++ " " ++ show b ++ " /n"
In the expression:
do tell "gcd " ++ show a ++ " " ++ show b ++ " /n"
return a
In an equation for ‘gcd'’:
gcd' a b
| b == 0
= do tell "gcd " ++ show a ++ " " ++ show b ++ " /n"
return a
| otherwise
= do tell "gcd " ++ show a ++ " " ++ show b ++ " /n"
gcd' b (a `mod` b)
答案 0 :(得分:3)
您的第一次尝试不起作用,因为函数应用程序优先于运算符。因此它被解析为:
(tell "gcd ") ++ (show a) ++ " " ++ (show b) ++ "\n "
在第二次尝试中,您每次都将字符串包装在一个单例列表中,然后编写一个String
的列表(所有这些列表都包含一个字符串,但是仍然不能使这些{{ 1}} s。
您可以在此处添加括号来解决该问题:
String
例如:
gcd' :: Int -> Int -> Writer String Int
gcd' a b = do
tell ("gcd " ++ show a ++ " " ++ show b ++ " \n")
if b == 0 then
return a
else
gcd' b (a `mod` b)
请注意,出于调试目的,您可以更方便地使用trace :: String -> a -> a
而不是Prelude Control.Monad.Trans.Writer.CPS> runWriter (gcd' 15 5)
(5,"gcd 15 5 \ngcd 5 0 \n")
,因为它可以更好地完成您想要的操作。