[英]Extracting `a` from Applicative `f a`
了解一下Haskell提供了以下練習:
讓我們嘗試實現一個獲取應用程序列表的函數,並返回一個以列表作為結果值的應用程序。
LYAH給出類型簽名sequenceA' :: (Applicative f) => [fa] -> f [a]
我開始與Applicative
,但不知道如何提取a
從fa
為所有一般的方式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
我怎樣才能提取a
從fa
那里f
是一個Applicative
?
你不能一般。 實際上,你給出的Maybe
例子就是一個很好的例子,因為它要求它是一個Num
實例。 一般來說,對於Maybe
Applicative
來說沒有意義,所以這將是一般解決方案的反例。 另一個反例是IO
。 IO
沒有有效的extract
實現。
要創建一個通用的函數來處理所有Applicative
實例,您必須能夠僅使用Applicative
及其超類Functor
方法來構造函數。 沒有辦法只使用fmap
, pure
和(<*>)
進行extract
。
沒有必要從應用程序仿函數中取出來實現這一目標。
關於applicative functors的好處是它們允許你在每個應用計算的結果上使用普通函數,所以
如果您有類型fa
, fb
, fc
應用c1
, c2
和c3
產生類型a
, b
和c
值v1
, v2
和v3
,
但實際上你想在值上使用函數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
。
您可以提取a
從fa
與模式匹配或評估,如果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.