Haskell-无法使用类似Monad的定义来定义类似于State Monad的函数 [英] Haskell - Unable to define a State monad like function using a Monad like definition

查看:106
本文介绍了Haskell-无法使用类似Monad的定义来定义类似于State Monad的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图通过尝试编写泛型版本的功能来理解Monad的概念,这些功能随后可能包含记录日志,更改状态的副作用.

I am trying to understand the concept of Monad by attempting to write generic version of functions that might be then include side effects to log, change state.

这是我想出的:(代码有点长,但是它可以显示我是如何理解monad的-这种方法可能不正确)

Here is what I came up with: (The code is bit long, but it is there to show how I approached understanding monad - and this approach may not be correct)

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'模式. 在这种情况下如何提出实现以匹配绑定运算符签名?

The function stBind' defined in the end does not fit the pattern of bind'. How can I come up with an implementation in this situation to match the bind operator signature?

推荐答案

冒着被破坏的风险,使State monad的定义达到顶峰可能很有趣,因为它在所有东西都变成变压器之前就已经存在:

At the risk of spoilers, it might be interesting to peak at the definition of the State monad as it existed before everything became transformer-ified:

newtype State s a = State { runState :: s -> (a, s) }

也就是说,状态为s的有状态动作会产生类型为a的值,它是从旧状态s到值新状态(a, s)的函数.

That is: a stateful action with state s that produces a value of type a is a function from the old state s to a value and a new state, (a, s).

从正确的State定义开始,应该使开发的其余部分更容易迷惑.

Starting from the correct definition for State should make the remainder of your development easier to puzzle through.

这篇关于Haskell-无法使用类似Monad的定义来定义类似于State Monad的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆