【问题标题】:Defining and using monadic structures on custom datatypes?在自定义数据类型上定义和使用一元结构?
【发布时间】:2016-12-14 17:20:56
【问题描述】:

我开始掌握函子、应用程序和单子。

这些例子只是为了说明基础:

data User a = Age a deriving (Show, Eq, Ord)

Functor(将非上下文函数应用于单个上下文数据类型):

instance Functor User where
  fmap f (Age a) = Age (f a)

functorFunction :: Int -> Int
functorFunction e = e + 1

main = do
 print $ fmap functorFunction (Age 22)

Applicative(将简单函数应用于多种上下文数据类型):

instance Applicative User where
  pure a = Age a
  (<*>) (Age a) = fmap a

applicativeFunction :: Int -> Int -> Int
applicativeFunction e1 e2 = e1 + e2

main = do 
  print $ pure (applicativeFunction) <*> (Age 44) <*> (Age 65)  

我已经通过learnyouahaskell 并没有能够找到一个简单的解释

1) 如何为我的“用户 a”类型定义 monad 结构,以及 2) monad 提供什么功能,例如,应用函子?

【问题讨论】:

标签: haskell monads functor


【解决方案1】:

1) 如何为我的“用户 a”类型定义 monad 结构

(初步说明:Learn You a Haskell 早于 Applicative 成为 Monad 的超类。因此,与本书所暗示的不同,使用最新版本的 GHC 不需要实现 return -- by默认和pure一样,那我就直接跳转到(&gt;&gt;=)了。)

关于具有非常通用类型的方法(例如 (&gt;&gt;=)...)的一个好处...

(>>=) :: Monad m => m a -> (a -> m b) -> m b

... 是它们太笼统了,以至于几乎没有明智的方法来实现它们——通常只有一种。如果我们针对您的类型专门针对 (&gt;&gt;=),我们会得到:

(>>=) @User :: User a -> (a -> User b) -> User b

所以(&gt;&gt;=) 应该采用User aa -&gt; User b 并使用它们生成User b。鉴于该函数需要一个a 值,首先要尝试的是寻找一个a 值来传递给它。我们确实有这样一个值:由Age 构造函数包裹在User a 值中的那个:

instance Monad User where
    (Age a) >>= f = f a

要良心编写Monad 实例,我们应该检查它是否遵循单子定律:

return a >>= f = f a

m >>= return = m

(m >>= f) >>= g = m >>= (\x -> f x >>= g)

这可以用(你最喜欢的)笔和纸来完成:

return a >>= f = f a
Age a >>= f = f a
f a = f a

m >>= return = m
Age a >>= return = Age a -- [*]
Age a >>= Age = Age a
Age a = Age a 

-- [*]: Both here and in the next law, we can replace 'm' by 'Age a'
--      because there is just one constructor. If there were more
--      (as in e.g. data Maybe a = Nothing | Just a), we would have
--      to check the law holds for all constructors.  

(m >>= f) >>= g = m >>= (\x -> f x >>= g)
(Age a >>= f) >>= g = Age a >>= (\x -> f x >>= g)
f a >>= g = (\x -> f x >>= g) a
f a >>= g = f a >>= g

2) monad 与应用函子相比提供了哪些功能?

这里我把它留给the question arrowd suggested。我只会注意到你的例子并没有给你足够的真正理解差异,因为 User 上下文太简单了,不能让你用 (&gt;&gt;=) 做任何有趣的事情(正如 Benjamin Hodgson 指出的那样,它与 @ 同构987654345@,虚拟函子)。 Maybe,被链接问题的接受答案使用,更具说明性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-15
    • 2021-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-06
    相关资源
    最近更新 更多