尝试在 Haskell 中定义自定义绑定运算符时出错

Error trying to define custom bind operator in Haskell

所以我最近一直在研究 monad,我对 Haskell 编程语言还很陌生。

这是我的代码:

import Data.List
import System.IO

f :: Int -> (Int, [Char])
f x = (x, ['a'])

g :: Int -> (Int, [Char])
g y = (y, ['b'])

(>>=) :: (Int -> (Int, [Char])) -> (Int -> (Int, [Char])) -> Int -> (Int, [Char])
(>>=) f1 f2 a =  f1 (fst (f2 a))

h :: Int -> (Int, [Char])
h x = (>>=) g f x

GHCI 编译器显示: 错误:

Ambiguous occurrence `>>='
It could refer to either `Prelude.>>='

我做错了什么? 我使用 monad 的方式正确吗?

为了正确回答这个问题,我们必须检查您假设的和实际的知识是否与 Haskell 社区对此知识的定义相匹配。

所以,首先,您显然了解什么是类型,并且您似乎对多态类型 相当了解。

因为 Monad 是类型类,并且类型类使用 多态类型 并且因为类型类也可以使用 代数数据类型 ,在尝试理解 Monad 之前,确保你对这些东西有深入的了解是个好主意。类型类与其他语言中的接口非常相似——它们定义了一组抽象的强制和可选函数(及其类型),特定类型类实例必须遵守这些函数。它们通常还会为您提供 "free" 功能以及其他功能的默认定义。他们非常非常酷:)

有很多好地方可以让您更好地理解什么是类型类。我会告诉你 http://www.happylearnhaskelltutorial.com/1/output_other_things.html as a simple introduction (full disclosure, I helped write this), and the typeclassopedia, which will also explain about Monads a bit more, too (and give you the requisite knowledge) https://wiki.haskell.org/Typeclassopedia

我还应该提一下,如果您有钱并且想要长时间的练习来充实您的理解,请查看 http://haskellbook.com — 它相当冗长,但可能对您非常有用,通常也是为了让您对 Haskell.

的基础知识有一个很好的工作理解

重要的是要认识到使用一个Monad实例和制作一个Monad实例,这就是您在上面尝试做的事情。

然后,还有 Monad 类型类本身的定义,通常在书中作为示例给出,它可以帮助您理解 Monad 实例是如何工作的。

最终您需要查找 Monad 类型类中包含的函数的一般定义,以完全理解它是如何工作的,但最好了解这三件事是完全分开的但人们经常将其描述为 "Monad"。 (例如,值 Just 5 可以被描述为一个单子值,但人们通常会说它是一个单子,即使这在技术上以一种微妙的方式不正确......因为 Maybe 有一个 Monad为它定义的实例,Just 5是一个Maybe值。你也可以谈谈Monad实例为Maybe的定义,看看它是如何实现的,甚至自己定义它,只要您确保在尝试通过执行以下操作之一定义它时不在范围内:在前奏中隐藏默认值 Maybe,不要导入序曲,或将您的 Maybe 版本命名为其他名称,例如 MyMaybe.

因此,我建议您先了解这三件事之间的区别。有了这些知识,阅读我给你的两个参考资料,从阅读使用类型类的代码开始,然后阅读一些使用 Monad 实例的代码——一些不同的类型给你一个直觉,然后继续自己重新实现一两个前奏曲 Monad,然后最终尝试创建自己的 Monad 类型类版本而不看前奏曲,这样您就可以测试自己对函数的理解。然后你会对它们有一个很好的理解:)

另外值得注意的是,在到达 Monad 之前处理类型类的路径可能是个好主意。您可能无论如何都必须这样做,但它们是 FunctorApplicative,最后是 Monad。您可以选择在 Functor 之前添加 SemigroupMonoid,但这只是为了让您更多地了解类型类,而不是理解 Monad 类型类的必要条件。

祝你好运!

您正在为 (>>=) 定义一个绑定,它已经被前奏所绑定(如上面的评论中所指出的)。

因此,您需要消除对它的每个引用的歧义。

为您的模块命名

module M where

然后,而不是写

h x = (>>=) g f x

使用其中之一

h x = (M.>>=) g f x

h x = (Prelude.>>=) g f x

选择您想要的 >>= 版本。

但是,我认为这不是你真正想要做的。此 (>>=) 将是一个与 Monad class.

无关的绑定