如何解釋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適合做網站開發嗎?有什麼優缺點?