I have recently posted a question about the >> operator, because even though I have read the LYAH walk the linee section I still have some gaps in my understanding. Below is some code/MVE that I have stumbled upon since which sparkled the following reflections. How come I can get the output that follows the code? will it not be the case that no arguments are provided to the bind operator, and hence that no str argument can be concatenated as they otherwise would have been using bind as seen in the >>= definition, and shouldn't the result therefor not be similar to expected result mentioned below:
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
Output:
ghci> runComputation (apply "print" [(IntVal 1), (IntVal 2)]) [("x", (IntVal 4)), ("y", (IntVal 3))]
(Right NoneVal,["1 2"])
Expected output
(Right NoneVal, [])
Furthermore why will extending the bind operator definition with an extra str' concatenation to this:
(Left e, str) -> (Left e, str)
(Right a, str) -> let (a', str') = runComputation (f a) env in (a', str++str'++str'))
and the apply with another >> like this:
apply "print" values = output (unwords [showValue x| x<-values]) >> output (unwords [showValue x| x<-values]) >> return NoneVal , not result in the following:
ghci> runComputation (apply "print" [(IntVal 1), (IntVal 2)]) [("x", (IntVal 4)), ("y", (IntVal 3))]
(Right NoneVal,["1 2","1 2","1 2", "1 2"])
rather than the actual:
ghci> runComputation (apply "print" [(IntVal 1), (IntVal 2)]) [("x", (IntVal 4)), ("y", (IntVal 3))]
(Right NoneVal,["1 2","1 2","1 2"])
with only 3 inputted elements.
Not really.
m >> n, by definition, ism >>= \_ -> n, so you can see what it does by replacingfin your definition with the constant function\_ -> n:So the only thing being ignored is the intermediate result
a. The generation of thestroutput happens as usual. (Using a bit of jargon, we might say it is part of the effect of the monadic computation, in contrast with any results of typeaobtained from it.)On your output duplicating bind example, you get three rather than four strings because that bind only duplicates the output from the second computation (
str'but notstr).(By the way, even though you have only meant this for the sake of illustration, it's worth noting the duplicating bind isn't lawful:
return a >>= f = f awon't hold, asreturn a >>= fwill have duplicated output whilef awon't, and the asymmetry of the duplication will also make the associativity law fail.)