Haskell 使用typeclass free monad重新绑定do表示法
可以使用显式字典传递重新绑定(>>=)并返回monad,如下所示:Haskell 使用typeclass free monad重新绑定do表示法,haskell,monads,typeclass,do-notation,Haskell,Monads,Typeclass,Do Notation,可以使用显式字典传递重新绑定(>>=)并返回monad,如下所示: {-# LANGUAGE RankNTypes #-} {-# LANGUAGE RebindableSyntax #-} module Lib where import Prelude hiding ((>>=), return) data MonadDict m = MonadDict { bind :: forall a b. m a -> (a -> m b) -> m b ,
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RebindableSyntax #-}
module Lib where
import Prelude hiding ((>>=), return)
data MonadDict m = MonadDict {
bind :: forall a b. m a -> (a -> m b) -> m b ,
ret :: forall a. a -> m a }
(>>=) :: (MonadDict m -> m a) -> (a -> (MonadDict m -> m b)) -> (MonadDict m -> m b)
return :: a -> (MonadDict m -> m a)
monadDictIO :: MonadDict IO
usage = let
monadicCode = do
ln <- const getLine
const . putStrLn $ ln
in monadicCode monadDictIO
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE RecordWildCards #-}
module Lib where
import Prelude hiding(return, fail, (>>=), (>>))
data MonadDict m = MonadDict
{ (>>=) :: forall a b. m a -> (a -> m b) -> m b
, (>>) :: forall a b. m a -> m b -> m b
, return :: forall a. a -> m a
, fail :: forall a. String -> m a
}
monadDictIO :: MonadDict IO
monadDictIO = ...
foo :: MonadDict m -> String -> m ()
foo = ...
usage = let
monadicCode m@MonadDict{..} = do
ln <- getLine
putStrLn ln
foo m ln
in monadicCode monadDictIO
{-#语言等级}
{-#语言可重新绑定语法#-}
模块库在哪里
导入前奏隐藏((>>=),返回)
数据MonadDict m=MonadDict{
绑定::对于所有AB.MA->(a->MB)->MB,
ret::对于所有a.a->m a}
(>>=)::(单体m->MA)->(a->(单体m->MB))->(单体m->MB)
return::a->(MonadDict m->ma)
monaddicio::MonadDict IO
用法=let
monadicCode=do
ln你可以这样做:
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RebindableSyntax #-}
module Lib where
import Prelude hiding ((>>=), return)
data MonadDict m = MonadDict {
bind :: forall a b. m a -> (a -> m b) -> m b ,
ret :: forall a. a -> m a }
(>>=) :: (MonadDict m -> m a) -> (a -> (MonadDict m -> m b)) -> (MonadDict m -> m b)
return :: a -> (MonadDict m -> m a)
monadDictIO :: MonadDict IO
usage = let
monadicCode = do
ln <- const getLine
const . putStrLn $ ln
in monadicCode monadDictIO
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE RecordWildCards #-}
module Lib where
import Prelude hiding(return, fail, (>>=), (>>))
data MonadDict m = MonadDict
{ (>>=) :: forall a b. m a -> (a -> m b) -> m b
, (>>) :: forall a b. m a -> m b -> m b
, return :: forall a. a -> m a
, fail :: forall a. String -> m a
}
monadDictIO :: MonadDict IO
monadDictIO = ...
foo :: MonadDict m -> String -> m ()
foo = ...
usage = let
monadicCode m@MonadDict{..} = do
ln <- getLine
putStrLn ln
foo m ln
in monadicCode monadDictIO
{-#语言等级}
{-#语言可重新绑定语法#-}
{-#语言记录通配符}
模块库在哪里
导入前奏隐藏(返回、失败、(>>=)、(>>))
数据MonadDict m=MonadDict
{(>>=)::对于所有a b.m a->(a->m b)->m b
,(>>)::对于所有工商管理硕士->工商管理硕士->工商管理硕士
,return::for all a.a->m a
,失败::对于所有a.字符串->m a
}
monaddicio::MonadDict IO
单加性=。。。
foo::MonadDict m->String->m()
foo=。。。
用法=let
单子码m@MonadDict{..}=do
ln简短且不正确的答案是将MonadDict m
参数从第二个参数的返回类型中删除到(>>=)
:
但这并不能真正解决所有语法问题。如果有人有一个类型为Monad m=>a->mb
的现有箭头,并通过显式字典,则该箭头的类型为a->(MonadDict m->mb)
,并且不能用作(>>=)
的第二个参数。如果有一个函数drop::(MonadDict m->mb)->mb
使其与第二个参数兼容,那么就没有理由传递MonadDict
s
您正在重新设计转换器,以读取MonadDict m
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
每次使用const
时,它相当于将ma
提升到ReaderT(MonadDict m)ma
。如果您使用lift
而不是const
编写示例,您的示例看起来就不会那么陌生了
usage = let
monadicCode = do
ln <- lift getLine
lift . putStrLn $ ln
in monadicCode monadDictIO
如果你给它自己的类型,你可以为它配备一个独立于底层m
的Monad
实例,并且省去rebindabletsyntax
newtype ReadMD m a = ReadMD {runReadMD :: MonadDict m -> m a}
instance Functor (ReadMD f) where
fmap = liftM
instance Applicative (ReadMD f) where
pure = return
(<*>) = ap
instance Monad (ReadMD m) where
m >>= k = ReadMD $ \d@MonadDict { bind = bind } -> bind (runReadMD m d) (\a -> runReadMD (k a) d)
return a = ReadMD $ \d@MonadDict { ret = ret } -> ret a
newtype ReadMD m a=ReadMD{runReadMD::MonadDict m->m a}
实例函子(ReadMD f),其中
fmap=liftM
实例应用程序(ReadMD f),其中
纯=返回
()=ap
实例Monad(ReadMD m)其中
m>>=k=ReadMD$\d@MonadDict{bind=bind}->bind(runReadMD m d)(\a->runReadMD(ka)d)
返回a=ReadMD$\d@MonadDict{ret=ret}->ret a
你肯定会想要更像(>>=)::MonadDict m->ma->(a->mb)->mb
,或者如果你有三个不同的字典,你打算怎么做?@DanielWagner我只使用过一次看到用法部分,我在最后传递字典通常是简单的不变量,比如“我只传递一个”请打字员帮你检查是件好事。我建议的类型是要求它这样做的一种方式。@DanielWagner您如何将多个单子添加m
s传递给>=
;只有一个是公开的,即最后的MonadDict m
参数;只要>>=
将参数传递给该读卡器并传递给其他两个读卡器,那么相同的字典将用于所有3个读卡器(>>=)
的类型与ReaderT(MonadDict m)m
的前奏曲(>>=)
相同,但有不同的实现。@Cirdec啊,你说得对:我完全误读了类型签名!有趣。事实证明,这甚至适用于-XRecordWildCards
:如果您分别调用bind
字段>=
和>
,您只需使用monadicCode monadict{..}=do…
。这是否是一个好主意,我不太确定,但所有这一切肯定是有趣的。