Haskell有在標準庫函數定義Functor
,Applicative
和Monad
實例(具體地,部分應用類型(->) a
),圍繞功能組成內置仿/應用性/單子實例。用例用於功能
理解這些實例是一個很好的彎曲練習,但我的問題在於這些實例的實際用途。我很樂意聽到人們使用這些實際代碼的現實場景。
Haskell有在標準庫函數定義Functor
,Applicative
和Monad
實例(具體地,部分應用類型(->) a
),圍繞功能組成內置仿/應用性/單子實例。用例用於功能
理解這些實例是一個很好的彎曲練習,但我的問題在於這些實例的實際用途。我很樂意聽到人們使用這些實際代碼的現實場景。
有時您想將a -> m b
(其中m
是Applicative
)的函數作爲Applicative
自己處理。編寫驗證器或解析器時經常發生這種情況。要做到這一點
一種方法是使用Data.Functor.Compose
,它寄生在的(->) a
和m
的Applicative
實例給出Applicative
實例組成:
import Control.Applicative
import Data.Functor.Compose
type Star m a b = Compose ((->) a) m b
readPrompt :: Star IO String Int
readPrompt = Compose $ \prompt -> do
putStrLn $ prompt ++ ":"
readLn
main :: IO()
main = do
r <- getCompose (liftA2 (,) readPrompt readPrompt) "write number"
print r
還有其他的方法,比如創建自己的NEWTYPE ,或者使用ready-madenewtypes,從基地或其他庫。
涉及Functor和Applicative功能實例的常見模式是例如(+) <$> (*2) <*> (subtract 1)
。當您必須使用單個值輸入一系列函數時,這非常有用。在這種情況下,上述相當於\x -> (x * 2) + (x - 1)
。雖然這非常接近LiftA2
,但您可以無限期地擴展此模式。如果你有一個f函數來接受像a -> a -> a -> a -> a -> b
這樣的5個參數,你可以像f <$> (+2) <*> (*2) <*> (+1) <*> (subtract 3) <*> (/2)
那樣做,並用一個值給它提供。就像在下面的情況一樣;
Prelude> (,,,,) <$> (+2) <*> (*2) <*> (+1) <*> (subtract 3) <*> (/2) $ 10
(12.0,20.0,11.0,7.0,5.0)
編輯:信用爲@Will內斯的礦井下的另一個話題評論再評論,來了應用性的功能上一個美麗的使用;
Prelude> let isAscending = and . (zipWith (<=) <*> drop 1)
Prelude> isAscending [1,2,3,4]
True
Prelude> isAscending [1,2,5,4]
False
感謝您的意見。所以你發佈的5元組例子。它可以改寫爲((x - >(x + 2,x * 2,x + 1,x-3,x/2))10' - 這裏的應用的優點是不需要重複'x'? –
@Eli Bendersky的主要區別是,在應用形式,如果你知道的主要功能有多少參數需要,整個事情是功能分解(即可以動態撰寫的參數,你喜歡的方式)在lambda形式,你必須同時手邊有一個可靠的lambda函數。 – Redu
你是說我們已經有了一個函數,比如'(,,,,)''而不必手工編寫lambda? –
的[讀卡器單子](http://hackage.haskell.org/package/mtl/docs/Control-Monad-Reader.html)基本上是一個NEWTYPE包裝紙圍繞'( - >)'。 – melpomene
我一直都在使用它們。可能你自己不知道:'.'只是'fmap'。 – Bergi
@Bergi:當然,我想這個問題是爲什麼,而不是使用它們只是利用 –