Pis*_*tor 0 monads haskell functional-programming side-effects
我最近发布了一个关于>>操作员的问题,因为尽管我已经阅读了 LYAH walk the linee 部分,但我的理解仍然存在一些差距。下面是我偶然发现的一些代码/MVE,因为它们引发了以下思考。我怎么能得到代码后面的输出?是否不会出现没有向绑定运算符提供参数的情况,因此无法str连接任何参数,否则它们会使用>>=定义中所示的绑定,并且结果不应该与预期的不相似结果如下:
import Control.Monad
import Data.List
data Value =
NoneVal
| IntVal Int
| ListVal [Value]
deriving (Eq, Show, Read)
data RErr = EBVar String | EBInt Int
deriving (Eq, Show)
newtype Compuptaton a = Computation {runComputation :: [(String, Value)] -> (Either RErr a, [String]) }
instance Monad Computation where
return a = Computation( \_ -> (Right a, []))
m >>= f = Computation(\env -> case runComputation m env of
(Left e, str) -> (Left e, str)
(Right a, str) -> let (a', str') = runComputation (f a) env in (a', str++str'))
showValue :: Value -> String
showValue (IntVal int) = show int
showValue (ListVal values) = "[" ++ intercalate ", " [showValue x| x<-values] ++ "]"
output :: String -> Computation ()
output s = Computation (\_ -> (Right (), [s]))
apply :: String-> [Value] -> Computation Value
apply "print" values = output (unwords [showValue x| x<-values]) >> return NoneVal
Run Code Online (Sandbox Code Playgroud)
输出:
ghci> runComputation (apply "print" [(IntVal 1), (IntVal 2)]) [("x", (IntVal 4)), ("y", (IntVal 3))]
(Right NoneVal,["1 2"])
Run Code Online (Sandbox Code Playgroud)
预期产出
(Right NoneVal, [])
Run Code Online (Sandbox Code Playgroud)
此外,为什么要使用额外的串联来扩展绑定运算符定义str':
import Control.Monad
import Data.List
data Value =
NoneVal
| IntVal Int
| ListVal [Value]
deriving (Eq, Show, Read)
data RErr = EBVar String | EBInt Int
deriving (Eq, Show)
newtype Compuptaton a = Computation {runComputation :: [(String, Value)] -> (Either RErr a, [String]) }
instance Monad Computation where
return a = Computation( \_ -> (Right a, []))
m >>= f = Computation(\env -> case runComputation m env of
(Left e, str) -> (Left e, str)
(Right a, str) -> let (a', str') = runComputation (f a) env in (a', str++str'))
showValue :: Value -> String
showValue (IntVal int) = show int
showValue (ListVal values) = "[" ++ intercalate ", " [showValue x| x<-values] ++ "]"
output :: String -> Computation ()
output s = Computation (\_ -> (Right (), [s]))
apply :: String-> [Value] -> Computation Value
apply "print" values = output (unwords [showValue x| x<-values]) >> return NoneVal
Run Code Online (Sandbox Code Playgroud)
和apply另一个>>这样的:
apply "print" values = output (unwords [showValue x| x<-values]) >> output (unwords [showValue x| x<-values]) >> return NoneVal,不会导致以下结果:
ghci> runComputation (apply "print" [(IntVal 1), (IntVal 2)]) [("x", (IntVal 4)), ("y", (IntVal 3))]
(Right NoneVal,["1 2","1 2","1 2", "1 2"])
Run Code Online (Sandbox Code Playgroud)
而不是实际的:
ghci> runComputation (apply "print" [(IntVal 1), (IntVal 2)]) [("x", (IntVal 4)), ("y", (IntVal 3))]
(Right NoneVal,["1 2","1 2","1 2"])
Run Code Online (Sandbox Code Playgroud)
只有 3 个输入元素。
是否不会出现没有向绑定运算符提供任何参数的情况,因此
str无法连接任何参数,否则它们将使用>>=定义中所示的绑定
并不真地。m >> n,根据定义,是,因此您可以通过在定义中m >>= \_ -> n替换为常量函数 来了解它的作用:f\_ -> n
m >> n = Comp(\env -> case runComp m env of
(Left e, str) -> (Left e, str)
(Right a, str) -> let (a', str') = runComp ((\_ -> n) a) env in (a', str++str'))
-- Applying (\_ -> n)
m >> n = Comp(\env -> case runComp m env of
(Left e, str) -> (Left e, str)
(Right _, str) -> let (a', str') = runComp n env in (a', str++str'))
Run Code Online (Sandbox Code Playgroud)
所以唯一被忽略的是中间结果a。输出的生成str如常进行。(用一点行话来说,我们可以说它是一元计算效果a的一部分,与从中获得的任何类型结果相反。)
在输出复制绑定示例中,您会得到三个而不是四个字符串,因为该绑定仅复制第二次计算的输出(str'但不复制str)。
(顺便说一句,即使您只是为了说明而这么说,但值得注意的是,重复绑定是不合法的:return a >>= f = f a不会成立,因为return a >>= f将有重复的输出,而f a不会,并且重复的不对称性也会使结合律失效。)