Haskell - 无法使用类似 Monad 的定义来定义类似 State Monad 的函数
Haskell - Unable to define a State monad like function using a Monad like definition
我试图通过编写函数的通用版本来理解 Monad 的概念,这些函数可能会包含副作用以记录、更改状态。
这是我想出的:(代码有点长,但它显示了我是如何理解 monad 的——这种方法可能不正确)
data Maybe' a = Nothing' | Just' a deriving Show
sqrt' :: (Floating a, Ord a) => a -> Maybe' a
sqrt' x = if x < 0 then Nothing' else Just' (sqrt x)
inv' :: (Floating a, Ord a) => a -> Maybe' a
inv' x = if x == 0 then Nothing' else Just' (1/x)
log' :: (Floating a, Ord a) => a -> Maybe' a
log' x = if x == 0 then Nothing' else Just' (log x)
sqrtInvLog' :: (Floating a, Ord a) => a -> Maybe' a
sqrtInvLog' x = case (sqrt' x) of
Nothing' -> Nothing'
(Just' y) -> case (inv' y) of
Nothing' -> Nothing'
(Just' z) -> log' z
-- Now attempt to simplify the nested case:
fMaybe' :: (Maybe' a) -> (a -> Maybe' b) -> Maybe' b
fMaybe' Nothing' _ = Nothing'
fMaybe' (Just' x) f = f x
-- using fMaybe':
sqrtInvLog'' :: (Floating a, Ord a) => a -> Maybe' a
sqrtInvLog'' x = (sqrt' x) `fMaybe'` (inv') `fMaybe'` (log')
-- now we can generalize the concept to any type, instead of just Maybe' by defining a Monad =>
class Monad' m where
bind' :: m a -> (a -> m b) -> m b
return' :: a -> m a
instance Monad' Maybe' where
bind' Nothing' _ = Nothing'
bind' (Just' x) f = f x
return' x = Just' x
-- using Monad sqrtInvLog'' can be written as:
sqrtInvLog''' :: (Floating a, Ord a) => a -> Maybe' a
sqrtInvLog''' x = (sqrt' x) `bind'` (inv') `bind'` (log')
-- Further lets attempt to use this for state maintenence and logging, logging:
-- first attempt the specific version:
data ST a = ST (a, Maybe' a) deriving Show
sqrtSt :: (Floating a, Ord a)=> a -> a -> ST a
sqrtSt st x = let r = sqrt' x in case r of
Nothing' -> ST (st, Nothing')
(Just' y) -> ST (st+y, (Just' y))
invSt :: (Floating a, Ord a)=> a -> a -> ST a
invSt st x = let r = inv' x in case r of
Nothing' -> ST (st, Nothing')
(Just' y) -> ST (st+y, (Just' y))
logSt :: (Floating a, Ord a)=> a -> a -> ST a
logSt st x = let r = log' x in case r of
Nothing' -> ST (st, Nothing')
(Just' y) -> ST (st+y, (Just' y))
-- let us first define function which is similar to bind and manipulates the state and invokes the given function:
stBind :: (Floating a, Ord a) => ST a -> (a->a->ST a) -> ST a
stBind (ST (a, Nothing')) _ = ST (a, Nothing')
stBind (ST (s, (Just' y))) f = f s y
sqrtInvLogSt :: (Floating a, Ord a) => a -> a -> ST a
sqrtInvLogSt st x = (sqrtSt st x) `stBind` (invSt) `stBind` (logSt)
-- stBind does not fit the pattern of bind
-- Another version:
sqrtSt' :: (Floating a, Ord a)=> ST a -> ST a
sqrtSt' (ST (st, Nothing')) = ST (st, Nothing')
sqrtSt' (ST (st, (Just' x))) = let r = sqrt' x in case r of
Nothing' -> ST (st, Nothing')
(Just' y) -> ST (st+y, (Just' y))
invSt' :: (Floating a, Ord a)=> ST a -> ST a
invSt' (ST (st, Nothing')) = ST (st, Nothing')
invSt' (ST (st, (Just' x))) = let r = inv' x in case r of
Nothing' -> ST (st, Nothing')
(Just' y) -> ST (st+y, (Just' y))
logSt' :: (Floating a, Ord a)=> ST a -> ST a
logSt' (ST (st, Nothing')) = ST (st, Nothing')
logSt' (ST (st, (Just' x))) = let r = log' x in case r of
Nothing' -> ST (st, Nothing')
(Just' y) -> ST (st+y, (Just' y))
-- define stBind' here
stBind' :: (Floating a, Ord a) => ST a -> (ST a->ST a) -> ST a
stBind' (ST (a, Nothing')) _ = ST (a, Nothing')
stBind' stx f = f stx
sqrtInvLogSt' :: (Floating a, Ord a) => ST a->ST a
sqrtInvLogSt' stx = (sqrtSt' stx) `stBind'` (invSt') `stBind'` (logSt')
-- Even this does not fit the pattern of bind,
最后定义的函数stBind'不符合bind'的模式。
在这种情况下,我怎样才能想出一个实现来匹配绑定运算符签名?
冒着剧透的风险,在一切都被转化之前就存在的 State
monad 的定义达到顶峰可能会很有趣:
newtype State s a = State { runState :: s -> (a, s) }
即:状态为 s
并产生类型为 a
的值的有状态操作是从旧状态 s
到值和新状态的函数,(a, s)
.
从 State
的正确定义开始应该会使您的开发的其余部分更容易理解。
我试图通过编写函数的通用版本来理解 Monad 的概念,这些函数可能会包含副作用以记录、更改状态。
这是我想出的:(代码有点长,但它显示了我是如何理解 monad 的——这种方法可能不正确)
data Maybe' a = Nothing' | Just' a deriving Show
sqrt' :: (Floating a, Ord a) => a -> Maybe' a
sqrt' x = if x < 0 then Nothing' else Just' (sqrt x)
inv' :: (Floating a, Ord a) => a -> Maybe' a
inv' x = if x == 0 then Nothing' else Just' (1/x)
log' :: (Floating a, Ord a) => a -> Maybe' a
log' x = if x == 0 then Nothing' else Just' (log x)
sqrtInvLog' :: (Floating a, Ord a) => a -> Maybe' a
sqrtInvLog' x = case (sqrt' x) of
Nothing' -> Nothing'
(Just' y) -> case (inv' y) of
Nothing' -> Nothing'
(Just' z) -> log' z
-- Now attempt to simplify the nested case:
fMaybe' :: (Maybe' a) -> (a -> Maybe' b) -> Maybe' b
fMaybe' Nothing' _ = Nothing'
fMaybe' (Just' x) f = f x
-- using fMaybe':
sqrtInvLog'' :: (Floating a, Ord a) => a -> Maybe' a
sqrtInvLog'' x = (sqrt' x) `fMaybe'` (inv') `fMaybe'` (log')
-- now we can generalize the concept to any type, instead of just Maybe' by defining a Monad =>
class Monad' m where
bind' :: m a -> (a -> m b) -> m b
return' :: a -> m a
instance Monad' Maybe' where
bind' Nothing' _ = Nothing'
bind' (Just' x) f = f x
return' x = Just' x
-- using Monad sqrtInvLog'' can be written as:
sqrtInvLog''' :: (Floating a, Ord a) => a -> Maybe' a
sqrtInvLog''' x = (sqrt' x) `bind'` (inv') `bind'` (log')
-- Further lets attempt to use this for state maintenence and logging, logging:
-- first attempt the specific version:
data ST a = ST (a, Maybe' a) deriving Show
sqrtSt :: (Floating a, Ord a)=> a -> a -> ST a
sqrtSt st x = let r = sqrt' x in case r of
Nothing' -> ST (st, Nothing')
(Just' y) -> ST (st+y, (Just' y))
invSt :: (Floating a, Ord a)=> a -> a -> ST a
invSt st x = let r = inv' x in case r of
Nothing' -> ST (st, Nothing')
(Just' y) -> ST (st+y, (Just' y))
logSt :: (Floating a, Ord a)=> a -> a -> ST a
logSt st x = let r = log' x in case r of
Nothing' -> ST (st, Nothing')
(Just' y) -> ST (st+y, (Just' y))
-- let us first define function which is similar to bind and manipulates the state and invokes the given function:
stBind :: (Floating a, Ord a) => ST a -> (a->a->ST a) -> ST a
stBind (ST (a, Nothing')) _ = ST (a, Nothing')
stBind (ST (s, (Just' y))) f = f s y
sqrtInvLogSt :: (Floating a, Ord a) => a -> a -> ST a
sqrtInvLogSt st x = (sqrtSt st x) `stBind` (invSt) `stBind` (logSt)
-- stBind does not fit the pattern of bind
-- Another version:
sqrtSt' :: (Floating a, Ord a)=> ST a -> ST a
sqrtSt' (ST (st, Nothing')) = ST (st, Nothing')
sqrtSt' (ST (st, (Just' x))) = let r = sqrt' x in case r of
Nothing' -> ST (st, Nothing')
(Just' y) -> ST (st+y, (Just' y))
invSt' :: (Floating a, Ord a)=> ST a -> ST a
invSt' (ST (st, Nothing')) = ST (st, Nothing')
invSt' (ST (st, (Just' x))) = let r = inv' x in case r of
Nothing' -> ST (st, Nothing')
(Just' y) -> ST (st+y, (Just' y))
logSt' :: (Floating a, Ord a)=> ST a -> ST a
logSt' (ST (st, Nothing')) = ST (st, Nothing')
logSt' (ST (st, (Just' x))) = let r = log' x in case r of
Nothing' -> ST (st, Nothing')
(Just' y) -> ST (st+y, (Just' y))
-- define stBind' here
stBind' :: (Floating a, Ord a) => ST a -> (ST a->ST a) -> ST a
stBind' (ST (a, Nothing')) _ = ST (a, Nothing')
stBind' stx f = f stx
sqrtInvLogSt' :: (Floating a, Ord a) => ST a->ST a
sqrtInvLogSt' stx = (sqrtSt' stx) `stBind'` (invSt') `stBind'` (logSt')
-- Even this does not fit the pattern of bind,
最后定义的函数stBind'不符合bind'的模式。 在这种情况下,我怎样才能想出一个实现来匹配绑定运算符签名?
冒着剧透的风险,在一切都被转化之前就存在的 State
monad 的定义达到顶峰可能会很有趣:
newtype State s a = State { runState :: s -> (a, s) }
即:状态为 s
并产生类型为 a
的值的有状态操作是从旧状态 s
到值和新状态的函数,(a, s)
.
从 State
的正确定义开始应该会使您的开发的其余部分更容易理解。