简体   繁体   English

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

[英]Error trying to define custom bind operator in Haskell

So I have been researching a lot about monads lately and I am very new to the Haskell-programming language. 所以我最近一直在研究monad,我对Haskell编程语言很陌生。

This is my code: 这是我的代码:

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

The GHCI-Compiler displays: error: GHCI编译器显示:错误:

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

What am I doing wrong? 我究竟做错了什么? Am I using monads in the correct way? 我是否以正确的方式使用monad?

You are defining a binding for (>>=) which is already bound by the prelude (as pointed out in the comments above). 您正在定义(>>=)绑定,该绑定已经被前奏绑定(如上面的注释中所指出的)。

So, you need to disambiguate each reference to it. 因此,您需要消除对它的每个引用的歧义。

Give your module a name 为您的模块命名

module M where

and then, instead of writing 然后,而不是写作

h x = (>>=) g f x

use either 使用其中之一

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

or 要么

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

to choose which version of >>= you want. 选择你想要的版本>>=

However , this is not what you actually want to do, I think. 但是 ,我认为这不是你真正想做的事情。 This (>>=) will be a binding which has nothing to do with the Monad class. 这个(>>=)将是一个与Monad类无关的绑定。

To answer this properly, we have to check that your assumed and actual knowledge match up with the definitions the Haskell community has for this knowledge. 为了正确回答这个问题,我们必须检查您的假设和实际知识是否与Haskell社区对此知识的定义相匹配。

So, to begin, you obviously understand what types are, and it seems like you understand polymorphic types reasonably well. 所以,首先,你显然明白了什么类型,似乎你理解多态类型相当好。

Because Monad is a typeclass, and typeclasses use polymorphic types and because typeclasses can also use algebraic data types , it's a good idea to make sure you have a firm understanding of those things before attempting to understand Monad . 因为Monad是一个类型类,并且类型类使用多态类型,并且因为类型类也可以使用代数数据类型 ,所以在尝试理解Monad之前确保你对这些事物有一个坚定的理解是个好主意。 Typeclasses are very similar to interfaces in other langauges - they define an abstract set of mandatory and optional functions (and their types) that a particular typeclass instance must adhere to. 类型类与其他语言中的接口非常相似 - 它们定义了一组特定类型类实例必须遵守的强制和可选函数(及其类型)。 Often they also give you "free" functionality with default definitions of other functions. 通常,它们还为您提供“免费”功能以及其他功能的默认定义。 They're very very cool :) 他们非常酷:)

There are many good places where you can gain a good understanding of what typeclasses are. 有很多好的地方可以让你很好地理解类型类。 I'd point you to 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://www.happylearnhaskelltutorial.com/1/output_other_things.html作为一个简单的介绍(完整的披露,我帮助写了这个),以及类型词典,它也将更多地解释Monads (并提供必要的知识) https://wiki.haskell.org/Typeclassopedia

I should mention, also, if you have the money and you want good lengthy exercises to really flesh out your understanding, check out http://haskellbook.com — it's fairly lengthy, but would probably be very useful for you, also generally to give you a good working understanding of the basics of Haskell. 我还要提一下,如果你有钱,而你想进行长时间的练习来真正充实你的理解,请查看http://haskellbook.com - 它相当冗长,但对你来说可能非常有用,一般来说也是如此。让您对Haskell的基础知识有一个很好的理解。

It's very important to realise that there is a big difference between using a Monad instance, of which the prelude contains many common ones, and making a Monad instance, which is what it appears you're trying to do above. 非常重要的是要意识到使用 Monad实例(前奏包含许多常见实例)和制作 Monad实例之间存在很大差异,这就是您在上面尝试做的事情。

Then, also, there's the definition of the Monad typeclass itself, often given as an example in books, and which can help you to understand how Monad instances work. 然后,还有Monad类型类本身的定义,通常在书中作为示例给出,它可以帮助您理解Monad实例的工作原理。

Eventually you'll need to look up the general definitions of the functions contained in the Monad typeclass anyway to fully understand how it's working, but it's good to keep an understanding that these three things are quite separate and yet often interchangeably described as "Monad" by people. 最后你需要查看Monad类型类中包含的函数的一般定义,以完全理解它是如何工作的,但是要理解这三个事物是完全独立的,并且经常可以互换地描述为“Monad”,这是很好的。由人。 (For example the value Just 5 could be described as a monadic value, but often people will just say it's a monad, even though that's technically incorrect in a subtle way... because Maybe has a Monad instance defined for it, and Just 5 is a Maybe value. You could also talk about the definition of the Monad instance for Maybe and look up how it's implemented, or even define it yourself, so long as you make sure you don't have it in scope when you try to defin it by doing one of the following: hide the default Maybe in the prelude, don't import the prelude, or name your version of Maybe something else, like MyMaybe . (例如,值Just 5可以被描述为monadic值,但通常人们只会说它是monad,即使这在技术上是不正确的......因为Maybe有一个为它定义的Monad实例,而且Just 5是一个Maybe值。你也可以谈论MaybeMonad实例的定义,并查看它是如何实现的,或者甚至自己定义它,只要你确保在尝试定义时没有它在范围内它通过执行下列操作之一:隐藏默认Maybe在前奏,不导入的前奏,或命名的版本, Maybe别的东西,像MyMaybe

So, I would recommend starting with understanding the difference between these three things. 所以,我建议首先要了解这三件事之间的区别。 Armed with that knowledge, read the two references I gave you, and start with reading code that uses typeclasses, then read some code that uses Monad instances — for a few different types to give you an intuition, then move on to reimplementing a prelude Monad or two yourself, then finally trying to create your own version of the Monad typeclass without looking at the prelude one so you can test your own understanding of the functions. 有了这些知识,请阅读我给你的两个参考文献,然后阅读使用类型类的代码,然后阅读一些使用Monad实例的代码 - 为几种不同的类型提供直觉,然后继续重新实现前奏Monad或者两个你自己,然后最终尝试创建你自己的Monad类型类的版本,而不是看前序,所以你可以测试自己对函数的理解。 Then you'll have a really good understanding of them :) 然后你会非常了解他们:)

Also worth noting that it's probably a good idea to tackle the path of typeclasses up to Monad before you get there. 另外值得注意的是,在你到达Monad之前解决类型的问题可能是一个好主意。 You'll probably have to do this anyway, but they are Functor , Applicative , and then finally Monad . 你可能不得不这样做,但他们是FunctorApplicative ,然后是Monad You can optionally add Semigroup and Monoid in before Functor , but that's just to give you more typeclass understanding more than a necessity for understanding the Monad typeclass. 您可以选择在Functor之前添加SemigroupMonoid ,但这只是为了让您更多地了解类型类,而不是理解Monad类型类的必要性。

Good luck! 祝好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM