【问题标题】:Implementing monad on recursive type在递归类型上实现 monad
【发布时间】:2019-05-14 18:30:30
【问题描述】:

我有一个递归类型:
data E a=A a (E a) (E a) | None
我的问题如下:
如果我想实现bind 运算符,我如何在给定操作函数的情况下对具体类型和递归类型进行操作?

instance Monad E where
    return x= A x None None 
    (>>=) None _ = None
    (>>=) (B t) f =  f t
    (>>=) (A x mx my) f = A {f x} (mx>>=f)  (my>>=f) --here !!!
                               ^
                            result is ma but slot requires concrete type

对于我来说,在A a (E a) (E a) 上为a 应用>>= 似乎我需要使用定制的function 来解开它。

我如何解决{f x}以便我解开f x 的结果以适合E 的具体插槽

我需要一个可以接受函数的方法:a-> ma 并将其传递给 (ma ->a)

    unwrap::E a->a
    unwrap None= what here ? ( i need a neutral element for any kind of a)
    unwrap (A x _ _)=x

【问题讨论】:

  • 那么您的f x 将在此处返回E a 类型的内容,因此您只需实现一个“解包”数据构造函数并对其执行操作的函数。
  • 你的意思是instance Monad E where ...
  • 那也应该是None >>= _ = None,而不是_ >>= None = None
  • 如果忽略 B 构造函数,这看起来像一个列表,因此您可能会通过查看 Monad [] 实现获得一些启发。这个数据类型应该代表什么——各种构造函数ABNone是什么意思?
  • 再次强调,如果您允许具有None 的空树,则不需要单独的叶构造函数:叶只是没有子树的AA x None None。可能重复:Monad instance for binary tree.

标签: haskell monads


【解决方案1】:

为了克服您的特定挑战,您应该尝试对 f x 的结果进行模式匹配。

(>>=) (A x mx) f = 
    case f x of
        A y my -> 
        B y -> 
        None -> 

现在你的问题可能比你带来的问题更大。现在有太多的选择,而不是他们的贫困。在A y my 的情况下,您必须以某种方式将ymymx 组合到最终结果中。很可能您想到的大多数方式都会违反法律。

在这种情况下,很难知道该怎么做。除非我清楚数据类型的含义,否则我很难实现 monad。我可以将列表“可视化”为 monad,因为 join(又名 (>>= id))只是串联

join :: [[a]] -> [a]
join [ [ x, y ], [z], [], [w, q] ] = [x, y, z, w, q]

但是对于任意代数数据类型,没有明确的路径。这种数据类型是从哪里来的? -- 你想从它的 monad 实例中得到什么?

【讨论】:

  • 或许可以使用data F a k = A a k | None然后定义type E a = Free (F a)来获得一些直觉。在这里,Pure 将在原始类型中扮演B 的角色。然而,这可能不是 OP 想要的(?)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-26
  • 1970-01-01
  • 1970-01-01
  • 2016-05-13
  • 1970-01-01
相关资源
最近更新 更多