尝试在 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
之前处理类型类的路径可能是个好主意。您可能无论如何都必须这样做,但它们是 Functor
、Applicative
,最后是 Monad
。您可以选择在 Functor
之前添加 Semigroup
和 Monoid
,但这只是为了让您更多地了解类型类,而不是理解 Monad
类型类的必要条件。
祝你好运!
您正在为 (>>=)
定义一个绑定,它已经被前奏所绑定(如上面的评论中所指出的)。
因此,您需要消除对它的每个引用的歧义。
为您的模块命名
module M where
然后,而不是写
h x = (>>=) g f x
使用其中之一
h x = (M.>>=) g f x
或
h x = (Prelude.>>=) g f x
选择您想要的 >>=
版本。
但是,我认为这不是你真正想要做的。此 (>>=)
将是一个与 Monad
class.
无关的绑定
所以我最近一直在研究 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
之前处理类型类的路径可能是个好主意。您可能无论如何都必须这样做,但它们是 Functor
、Applicative
,最后是 Monad
。您可以选择在 Functor
之前添加 Semigroup
和 Monoid
,但这只是为了让您更多地了解类型类,而不是理解 Monad
类型类的必要条件。
祝你好运!
您正在为 (>>=)
定义一个绑定,它已经被前奏所绑定(如上面的评论中所指出的)。
因此,您需要消除对它的每个引用的歧义。
为您的模块命名
module M where
然后,而不是写
h x = (>>=) g f x
使用其中之一
h x = (M.>>=) g f x
或
h x = (Prelude.>>=) g f x
选择您想要的 >>=
版本。
但是,我认为这不是你真正想要做的。此 (>>=)
将是一个与 Monad
class.