簡體   English   中英

從Applicative`fa`中提取`a`

[英]Extracting `a` from Applicative `f a`

了解一下Haskell提供了以下練習:

讓我們嘗試實現一個獲取應用程序列表的函數,並返回一個以列表作為結果值的應用程序。

LYAH給出類型簽名sequenceA' :: (Applicative f) => [fa] -> f [a]

我開始與Applicative ,但不知道如何提取afa為所有一般的方式Applicative的。

所以,我把它實現為一個Maybe 當然,這對所有'Applicative'都是不可接受的。

import Control.Applicative

sequenceA' :: (Num a) =>  [Maybe a] -> Maybe [a] 
sequenceA' []  = pure []
sequenceA' xs = pure $ [extract' x | x <- xs ]

extract' :: (Num a) => Maybe a -> a 
extract' x  = case x of 
      Just y  -> y
      Nothing -> 0

我怎樣才能提取afa那里f是一個Applicative

你不能一般。 實際上,你給出的Maybe例子就是一個很好的例子,因為它要求它是一個Num實例。 一般來說,對於Maybe Applicative來說沒有意義,所以這將是一般解決方案的反例。 另一個反例是IO IO沒有有效的extract實現。

要創建一個通用的函數來處理所有Applicative實例,您必須能夠僅使用Applicative及其超類Functor方法來構造函數。 沒有辦法只使用fmappure(<*>)進行extract

沒有必要從應用程序仿函數中取出來實現這一目標。

關於applicative functors的好處是它們允許你在每個應用計算的結果上使用普通函數,所以
如果您有類型fafbfc應用c1c2c3
產生類型abcv1v2v3
但實際上你想在值上使用函數g :: a -> b -> c -> d
生產g v1 v2 v3 :: d ,然后就可以了

g <$> c1 <*> c2 <*> c3

其類型為fd

所以我們可以使用函數(:)將我們的應用程序列表中的第一個值與其余的一起加入,這樣你就可以做一些像(:) <$> thingThatGivesFirstValue <*> thing that gives the rest of the list 因此,如果您在應用程序列表上進行模式匹配,那將是一個很好的遞歸。

sequenceA' :: (Applicative f) => [f a] -> f [a]
sequenceA' [] = -- just give the empty list
sequenceA' (c:cs) = -- hmm. What could go here then?

所以你應該得到

ghci> sequenceA' [getLine, getLine, getLine]
Hello
there
everyone
["Hello","there","everyone"]
ghci> sequenceA' [Just 3, Just 4, Just 5]
Just [3,4,5]

這是一個示例函數,可以幫助您處理recursice案例:

nth :: Applicative f => f Int -> f [a] -> f a
nth wrappedInt wrappedList = (!!) <$> wrappedInt <*> wrappedList

因此,您無需解包任何內容或獲取值,操作符<$> and <*>讓您在內部執行任何操作。

nth (Just 3) (Just "Hello") == 'l'

這是一個提示:

foo :: Applicative f => f Int -> f Int -> f Int
foo fx fy = (+) <$> fx <*> fy    -- apply + "under" the functor

bar :: Applicative f => f a -> f [a] -> f [a]
bar fx fxs = ??? <$> fx <*> fxs  -- apply ??? "under" the functor

sequenceA' :: Applicative f => [f a] -> f [a]
sequenceA' []     = pure []   -- as in your solution
sequenceA' (x:xs) = let y  = x             -- :: f a
                        ys = sequenceA' xs -- :: f [a]
                    in ???

我在最后一個函數中使用let來闡明所涉及的類型。 你填寫后??? 你當然可以刪除let

您可以提取afa與模式匹配或評估,如果f不是IO

import Control.Applicative
import System.IO
import Control.Monad.ST

-- with AndrewC sequenceA' definition

sequenceA' :: (Applicative f) => [f a] -> f [a]
sequenceA' [] = pure []
sequenceA' (c:cs) = (:) <$> c <*> sequenceA' cs

seqOfMaybes :: [Maybe a] -> [a]
seqOfMaybes listOfMb = case sequenceA' listOfMb of
                   Nothing -> []
                   Just list -> list


-- sequencing ST computations

compute :: a -> ST s a
compute x = return x

seqOfSTData :: [Int] -> [Int]
seqOfSTData vals = runST $ (sequenceA' (map compute vals) :: ST s [Int])


-- but you cannot escape the applicative f if f is IO

readAnInt :: IO Int
readAnInt = putStrLn "give me an Int>" >> hFlush stdout >> getLine >>= (return . read)

seqOfIO :: [IO a] -> IO [a]
seqOfIO listOfIO = sequenceA' listOfIO

main :: IO ()
main = do
        print $ seqOfMaybes [Just 3, Just 4, Just 5]
        print $ seqOfSTData [1,2,3]
        seqOfIO [readAnInt, readAnInt] >>= print

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM