如何解釋Haskell中的單子?

既然題主想要容易明白的答覆,我猜題主大概是還在學習階段。那我就只管即便用最大略的語言表明單子(Monad)及其應用場景。

結論:

在haskell中,Monad也只是一個有本身特別性子的typeclass。要是想要一個範例是monad的,必須實現Monad範例類,而實現Monadtypeclass,只需至少實現(=)函數即可。

(=)::ma-(a-mb)-mb有了這個見解,你就可以實現本身的monad了。

而什麼時間要把範例定義為functor?什麼時間定義為applicative?什麼時間定義為monad?駕馭以下幾個點:

functor範例辦理的是怎樣將一個incontext的value(如Just1)輸入到平凡function中(如(+2)),並得到一個incontext的value(如Just3)。例子:

fmap(+2)Just1

applicative範例辦理的是怎樣將一個incontext的value(如Just1)輸入到只返回平凡value的incontext的function中(如Just(+2)),並得到一個incontext的value(如Just3)。例子:

Just(+2)*Just1

monad範例辦理的是怎樣將一個incontext的value(如Just3)輸入到只返回incontext的value的function中(如doublex=Just(x*2)),並得到一個incontext的value(如Just6)。例子:

Just3=double

------------------------------------------------------

要想明白Monad,最好先明白兩個相干的見解:Functor和Applicative。

你和我通過一個例子引入:對付一個常數1,你和我可以將其輸入函數(+2):

(+2)13很大略,沒有任何題目。

那麼,要是常數1是在一個context里呢?比如是在Maybe範例里:

dataMaybea=Justa|Nothing那麼,1會被表現成Just1,這時要是大略的用

(+2)Just1就會報錯:

Nontype-variableargumentintheconstraint:Num(a-Maybea)怎麼辦?

1.Functor

對付上面的題目,你和我可以用fmap來辦理。fmap可以從context里提取出value,謀略,再將謀略出的值放回context。

fmap(+2)Just1Just3你和我得到了結果Just3.

為什麼fmap可以從context中提取value?它是怎麼做到的?規矩是什麼?

你和我先看fmap函數出自那邊:

:tfmapfmap::Functorf=(a-b)-fa-fb那麼Functor是什麼?

你和我再去查Hoogle:

classFunctorfwhere

Minimalcompletedefinition

Methods

fmap::(a-b)-fa-fb

($)::a-fb-fa

......

可以如許明白這段定義:對付一個Functor範例的數據範例f,至少必要實現fmap。對付fmap函數,此中第一個輸入(a-b)是一個平凡函數,比如(+2);第二個輸入fa是一個Functor,比如Just1;末了返回一個Functor,比如Just3。

對付Functor如許的類,你和我稱之為typeclass(範例類)。typeclass有點像Java的interface:實現這個介面要實現此中的要領。,

回到你和我的例子,Maybe範例著實是Functor範例的。你和我可以查實現Maybe的源代碼去驗證一下:

instanceFunctorMaybewherefmap_Nothing=Nothingfmapf(Justa)=Just(fa)的確云云。這便是為什麼運行fmap(+2)(Just1)可以得到Just3。

以是總結一下,Functor可以辦理的題目是,當value被放在一個context中的時間(比如Maybe範例的Just1),你和我怎樣將其輸入一個平凡的function運算(如(+2)),並得到incontext的輸出(如Just3)。

那麼你和我進一步思量,要是function也被放在了一個context中了怎麼辦?

2.Applicative

比如如許的一個function:

Just(+2)要是想將Just1輸入,直接寫

Just(+2)Just1肯定是不可的。怎樣辦理這個題目?

你和我可以用函數*來辦理。

Just(+2)*Just1Just3同樣,要是去查*來自那邊,你和我會發明它是Applicative的一個要領:

Afunctorwithapplication,providingoperationsto

(*)::f(a-b)-fa-fb

......也便是說,一個Applicative範例的數據範例,必須實現*要領。這和Functor是同等的,Applicative也是一種typeclass。同樣你和我可以通過Maybe範例的實現來驗證它也是Applicative範例的:

instanceApplicativeMaybewherepure=JustJustf*m=fmapfmNothing*_m=NothingJust_m1*m2=m2Nothing*_m2=Nothing

總結一下,Applicative可以辦理的題目是,要是當value被放在一個context中(如1被放入Maybe範例,變為Just1),並且function也被放在一個context中(如(+2)被放入Maybe範例,變為Just(+2))時,怎樣運算並得到輸出。

你和我細緻到,*函數的value是在右邊,function是在左邊的。

那你和我進一步思量,要是你和我想要value在左邊,並且函數的輸出是一個incontext的值(比如Just3這種情勢)呢?

3.Monad

上面的環境,是可以用=函數(也叫bind函數)來辦理的。

舉個例子,倘若你和我有一個double函數:

doublex=Just(x*2)它的輸出是Maybe範例的。

那麼你和我想將Just1舉行double怎麼做?用以下的代碼即可:

Just1=doubleJust2你和我得到了Just2。沒錯,=函數是Monad的一個要領,其定義為:

(=)::ma-(a-mb)-mb而Monad的定義如下:

Minimalcompletedefinition

Methods

(=)::forallab.ma-(a-mb)-mb

()::forallab.ma-mb-mb

return::a-ma

從定義中你和我可以看出,Monad也是一個typeclass,那麼作為typeclass,一個monad範例的數據範例,必須實現其要領。Monad本身定義里寫的很明白,「這是一個來自範疇學的見解,不過從編程角度看最好將其視作一組舉動的抽象數據範例」。然而這句話到底怎麼明白?

說白了,在haskell里,一個monad便是一個參數化的範例m,以及一個必須實現的函數(=)

(=)::ma-(a-mb)-mb沒了。

舉個例子,要是你和我的參數化範例m是Maybe,(=)根據

(=)::Maybea-(a-Maybeb)-Maybeb來實現,那麼你和我得到的便是一個Maybemonad。

monad有很多好的性子,比如要是你和我想連續多次做double操縱,用Applicative就會有點貧苦,但是用Monad就很大略:

Just1=double=double=double=doubleJust16

固然,monad能做的事變遠不止這麼一點,相干也另有其他很多見解,比如將monads連合起來的要領monadtransformers,不過這便是別的一回事了。

結論:

在haskell中,Monad也只是一個有本身特別性子的typeclass。要是想要一個範例是monad的,必須實現Monad範例類,而實現Monadtypeclass,只需至少實現(=)函數即可。

(=)::ma-(a-mb)-mb有了這個見解,你就可以實現本身的monad了。

而什麼時間要把範例定義為functor?什麼時間定義為applicative?什麼時間定義為monad?駕馭以下幾個點:

functor範例辦理的是怎樣將一個incontext的value(如Just1)輸入到平凡function中(如(+2)),並得到一個incontext的value(如Just3)。例子:

fmap(+2)Just1

applicative範例辦理的是怎樣將一個incontext的value(如Just1)輸入到只返回平凡value的incontext的function中(如Just(+2)),並得到一個incontext的value(如Just3)。例子:

Just(+2)*Just1

monad範例辦理的是怎樣將一個incontext的value(如Just3)輸入到只返回incontext的value的function中(如doublex=Just(x*2)),並得到一個incontext的value(如Just6)。例子:

Just3=double

答覆很浮淺,乃至有很多地方是通過徵象倒推緣故起因,但盼望能幫到題主明白Monad的見解。

-------------------------------------

在其他答主的批評區看到一個很故意思的題目:為什麼大多數講義都用Maybe範例來作為functor,applicative和monad的舉例?由於Prelude實現了FunctorMaybe,ApplicativeMaybe和MonadMaybe,以是Maybe既是functor,又是applicative,還是monad,舉例最方便嘛。



推薦閱讀:

Haskell的Pipe/Conduit是什麼?
PureScript 是什麼?有什麼特性
[C++]代數數據類型與模式匹配
Haskell 怎麼推導函數類型呢?
Haskell適合做網站開發嗎?有什麼優缺點?

TAG:編程 | 編程語言 | Haskell | 計算機 |