簡體   English   中英

使用Applicative和Functor的Haskell函數

[英]Haskell function using Applicative and Functor

我有一個練習題,給我一個函數:

sequence :: Applicative f => [f a] -> f[a]
sequence = foldr (_hole (:)) (pure [])

問題說:

"What type is required for the function that needs to be placed at 
_hole in the following expression? Also give a definition for the 
expression using  and <$> and <*>".

我在理解問題所在時遇到問題。 因此,對於我嘗試過的操作,我假設由於使用了foldr而需要指定運算符,因此我假設其類似於sequence = foldr((+)(:))(pure [])。

然后為表達式的定義,我寫了類似的東西:

sequence :: <*> f => [f a] -> f[a]
sequence = foldr <$> pure []

我很確定我不是100%正確的,因此希望在任何更正上對此有所幫助。

本練習希望您假設某個值_hole在某處定義,並且上面的代碼進行檢查。 然后,目標是確定_hole的類型。 然后,它將詢問_hole的可能定義。

例如,如果我們被給予

foo :: Int
foo = 3 + _hole

答案應該是_hole :: Int ,因為這是使上面的代碼正常工作所需要的。 對於定義, _hole = 2是可以的。

相反,在

foo :: Int -> Bool
foo = const _hole "hello" True

那么我們需要_hole :: Bool -> Int -> Bool ,例如_hole = \\bi -> b

您自己的代碼更加復雜,因此最好寫下所有步驟:

sequence :: Applicative f => [f a] -> f[a]
sequence = foldr (_hole (:)) (pure [])

這里使用文件foldr ,(在列表中)具有類型

foldr :: (b -> c -> c) -> c -> [b] -> c

要輸入檢查,參數必須具有類型

_hole (:) :: b -> c -> c
pure [] :: c

僅使用兩個參數調用的foldr的結果是

sequence :: [b] -> c

因為這必須與上面的sequence類型匹配,所以我們得到

[b] = [f a]
c = f [a]

因此, b = fa

_hole (:) :: f a -> f [a] -> f [a]
pure [] :: f [a]

pure []零件類型將按原樣檢查。 另一方面,我們需要

_hole :: (type of (:)) -> f a -> f [a] -> f [a]

即因為對於任何d (:) :: d -> [d] -> [d] ,我們得到

_hole :: (d -> [d] -> [d]) -> f a -> f [a] -> f [a]

d可以任意選擇。 但是,選擇d=a是“自然的”,這樣我們得到

_hole :: (a -> [a] -> [a]) -> f a -> f [a] -> f [a]

現在,我們需要編寫一個定義_hole fxy = ?? <$><*> 本質上,我們需要從庫中重新實現liftA2 現在您應該可以解決最后一部分了。

讓我們一步一步地做,逐步發現我們定義中涉及的實體的類型。 我們被給予

sequence :: Applicative f => [f a] -> f [a]               --  (1)
sequence = foldr (_hole (:)) (pure [])                    --  (2)

因此對於某些gsequence = mksequence g g

mksequence g xs = foldr (g (:)) (pure []) xs              --  (3)

mksequence g [a,b,...,n] = r where                        --  (4)
    r = g (:) a $ g (:) b $ ... $ g (:) n (pure [])       --  (5)

mksequence g [a] = g (:) a (pure [])                      --  (6)

mksequence g []  = pure []                                --  (7)

-- [a,b,...,n] :: [f a]                     <-(4,1)       --  (8)
--  a,b,...,n  ::  f a                      <-(8)         --  (9)
--  r          :: f [a]                     <-(4,1)       --  (10)
-- pure []     :: f [a]                     <-(7,1)       --  (11)
-- g (:)       :: f a -> f [a] -> f [a]     <-(6,8,11,1)

最后,我們找到了g (:)的類型! 與它比較

(<*>)  :: f (a -> t) -> f a -> f t          , _A :: f (a -> t)
(_A <*> _C)                 :: f t          , _C :: f  a
(_B <*> _C)                 :: f (t -> s)   , _B :: f (a -> (t -> s))
((_B <*> _C) <*> _D)        :: f       s    , _D :: f        t

這樣我們就可以了

\ _B _C _D -> ((_B <*> _C) <*> _D)  
          :: f (a -> (t  ->  s)) -> f a -> f  t  -> f  s
   g ((:) ::    a -> [a] -> [a]) :: f a -> f [a] -> f [a]

簽名幾乎匹配! 只需輕輕一點,我們就可以

g (:) = (\ _B _C _D -> ((_B <*> _C) <*> _D)) (pure (:))

因此,概括地說

g  f2  fa  ft  =  pure f2  <*>  fa  <*>  ft

因為(<*>)關聯到左側。 重新檢查類型,

g  f2  fa  ft  =  pure f2  <*>  fa  <*>  ft
               =       f2  <$>  fa  <*>  ft

-- fa                 :: f a
-- f2                 ::   a -> t -> s
-- f2 <$> fa          :: f     (t -> s)
-- ft                 :: f      t
-- (f2 <$> fa) <*> ft :: f           s

實際上,此定義已經存在,並被命名為liftA2用於將二進制函數( f2 )“提升”為適用的“上下文”( f ):

           f2 ::   a ->   t ->   s
    liftA2 f2 :: f a -> f t -> f s

暫無
暫無

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

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