Haskells绑定操作符和>>操作符及其关系

lnlaulya  于 2023-08-06  发布在  其他
关注(0)|答案(1)|浏览(142)

我最近发布了一个关于>>运算符的问题,因为即使我已经阅读了LYAH walk the linee部分,我仍然有一些理解上的差距。下面是我偶然发现的一些代码/MVE,它们引发了以下思考。为什么我可以得到代码后面的输出?如果bind操作符没有提供参数,那么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'串联来扩展bind运算符定义:

(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个输入元素。

pvabu6sv

pvabu6sv1#

如果没有为bind操作符提供任何参数,那么str参数就不能连接起来,否则它们将使用bind,如>>=定义中所示
根据定义,m >> nm >>= \_ -> 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'))

字符串
因此,唯一被忽略的是中间结果astr输出的生成与往常一样。(使用一些术语,我们可以说它是一元计算的effect的一部分,与从它获得的任何a类型的结果相反。
在输出复制绑定的示例中,您将得到三个而不是四个字符串,因为该绑定仅复制第二次计算的输出(str',而不是str)。
(By顺便说一句,即使你只是为了说明而这样做,但值得注意的是,复制绑定是不合法的:return a >>= f = f a不会成立,因为return a >>= f会有重复的输出,而f a不会,而且重复的不对称性也会使结合律失效。

相关问题