如何在 Haskell 中为具有记录语法的类型定义 `bind`?

How to define `bind` for a type with record syntax in Haskell?

我在解决 Haskell 课程中的 Monad 作业时完全卡住了。有一个示例数据类型,我想为其定义特定于 Monad 的函数:

data MyMonad a = MyMonad { func :: String -> a }

instance Functor MyMonad where
    fmap f (MyMonad x) = MyMonad (\a -> f (x a))   

instance Applicative MyMonad where
    pure x = MyMonad (\a -> x)
    (MyMonad f) <*> (MyMonad g) = MyMonad (\a -> (f a)(g a))

instance Monad MyMonad where
    return x = MyMonad (\a -> x)
    MyMonad x >>= f = f (\a -> x a) --my wrong definition 

一旦声明了 Functor 和 Applicative 实例,我就尝试为 Monad 做同样的事情,但是......我一点也不了解如何将记录语法 func 放入其中f 函数。到目前为止,我将 bind 视为在将其映射到 f 之前获取 MyMonadx 的函数。据我所知,这只是任何 Monad 的一个关键特性——能够将一些值从一种数据类型上下文放入另一种数据类型上下文。老实说,我知道 Monad 实例中 [a], Maybebind 定义和其他几种永远存在的类型。是的,我清楚地看到 Monad class 服务的共同目的是什么。但是,我需要在这个特定案例中得到任何建议,只是为了增强我对处理记录之类的方式的理解。

MyMonad x中的x的类型为String -> a,而f的类型为a -> MyMonad b,因此我们应该return一个MyMonad b(包装函数 String -> b).

因此,我们应该构建一个将 s :: String 映射到 b 的函数。我们可以先将 s 传递给 x 函数,然后检索类型为 a 的值。接下来我们可以使用 a 作为参数调用 f,然后检索 MyMonad g。然后我们可以将 s 应用到 g.

因此我们可以将 Monad 实例实现为:

instance Monad MyMonad where
    return x = MyMonad (\a -> x)
    MyMonad x >>= f = MyMonad (<b>\s -> let MyMonad g = f (x s) in g s</b>)

因为你定义了一个 "getter" func :: MyMonad a -> a -> String,我们可以使用 getter 而不是使用 let … in … 表达式来 "unwrap" 输出值MyMonad 数据构造函数的:

instance Monad MyMonad where
    return x = MyMonad (\a -> x)
    MyMonad x >>= f = MyMonad (<b>\s -> func (f (x s)) s</b>)