从Applicative“f a”中提取“a”

时间:2014-07-28 01:18:12

标签: haskell

Learn You a Haskell提供以下练习:

  

让我们尝试实现一个带有一个应用程序和列表的函数   返回一个以列表作为结果值的应用程序。

LYAH给出了类型签名sequenceA' :: (Applicative f) => [f a] -> f [a]

我从Applicative开始,但不确定如何以a的方式从f a中提取所有Applicative的{​​{1}}。

所以,我将其实现为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 f a f中提取Applicative

4 个答案:

答案 0 :(得分:10)

你不能一般。实际上,您提供的Maybe示例是一个很好的示例,因为它要求它是Num实例。对于Maybe Applicative一般来说没有意义,所以这将是一般解决方案的反例。另一个反例是IOextract没有有效的IO实施。

要创建一个足以使用所有Applicative个实例的函数,您必须能够仅使用Applicative及其超类Functor中的方法构造函数。 。没有办法extract仅使用fmappure(<*>)

答案 1 :(得分:6)

没有必要从应用仿函数中取出来实现这一点。

关于applicative functors的好处是它们允许你在每个应用计算的结果上使用普通函数,所以
如果你有c1c2c3类型f af bf c的申请人 产生v1v2v3类型的abc值, 但实际上你想在值上使用函数g :: a -> b -> c -> d 生成g v1 v2 v3 :: d,然后就可以了

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

,其类型为f d

因此,我们可以使用函数(:)将我们的应用程序列表中的第一个值与其余值一起加入,这样您就可以执行(:) <$> 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'

答案 2 :(得分:2)

这是一个提示:

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

答案 3 :(得分:0)

如果a不是IO

,您可以使用模式匹配或评估从f a中提取f
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