我最近发布了一个关于
>>
操作员,因为即使我读过LYAH步行路线部分,我的理解仍有一些差距。以下是我偶然发现的一些代码/MVE,它引发了以下思考。为什么我可以得到代码后面的输出?难道没有向绑定运算符提供任何参数,因此没有
str
参数可以连接起来,否则它们将使用bind,如
>>=
定义,其结果不应该与下面提到的预期结果不相似吗
import Control.Monad
import Data.List
data Value =
NoneVal
| IntVal Int
| ListVal [Value]
deriving (Eq, Show, Read)
type FName = String
data RError = EBadVar String | EBadFun String | EBadArg String
deriving (Eq, Show)
newtype Comp a = Comp {runComp :: [(String, Value)] -> (Either RError a, [String]) }
instance Monad Comp where
return a = Comp( \_ -> (Right a, []))
m >>= f = Comp(\env -> case runComp m env of
(Left e, str) -> (Left e, str)
(Right a, str) -> let (a', str') = runComp (f a) env in (a', str++str'))
-- You shouldn't need to modify these
instance Functor Comp where
fmap = liftM
instance Applicative Comp where
pure = return; (<*>) = ap
showValue :: Value -> String
showValue (IntVal int) = show int
showValue (ListVal values) = "[" ++ intercalate ", " [showValue x| x<-values] ++ "]"
output :: String -> Comp ()
output s = Comp (\_ -> (Right (), [s]))
-- Helper functions for interpreter
apply :: FName -> [Value] -> Comp Value
apply "print" values = output (unwords [showValue x| x<-values]) >> return NoneVal
输出:
ghci> runComp (apply "print" [(IntVal 1), (IntVal 2)]) [("x", (IntVal 4)), ("y", (IntVal 3))]
(Right NoneVal,["1 2"])
预期输出
(Right NoneVal, [])
此外,为什么要用额外的
str'
连接到:
(Left e, str) -> (Left e, str)
(Right a, str) -> let (a', str') = runComp (f a) env in (a', str++str'++str'))
以及
apply
与另一个
>>
像这样:
apply "print" values = output (unwords [showValue x| x<-values]) >> output (unwords [showValue x| x<-values]) >> return NoneVal
,不会导致以下情况:
ghci> runComp (apply "print" [(IntVal 1), (IntVal 2)]) [("x", (IntVal 4)), ("y", (IntVal 3))]
(Right NoneVal,["1 2","1 2","1 2", "1 2"])
而不是实际的:
ghci> runComp (apply "print" [(IntVal 1), (IntVal 2)]) [("x", (IntVal 4)), ("y", (IntVal 3))]
(Right NoneVal,["1 2","1 2","1 2"])
只有3个输入元素。