2017-12-08 6 views
4

私は素晴らしいHaskell Programming from first principlesを読んで私の人生の時間を持っていると私は私がちょうど離れ(ページ1286電子書籍リーダーを)取ることができないんだけど、次の例で来た:それは明らかである`(fmap。fmap)sumの型はちょうど[1、2、3]`が働くのはなぜですか?

Prelude> (fmap . fmap) sum Just [1, 2, 3] 
Just 6 

私にはどのように次のような作品:

Prelude> fmap sum $ Just [1,2,3] 
Just 6 

そして、私はすでに手動タイプがどのように機能するかを理解するために(fmap . fmap)を解体。しかし、これを「2倍にする」と考えると、JustとListの両方のデータコンストラクタを取り上げているので意味がありません。

私はghciに次のように出て型付け:

Prelude> :t (fmap . fmap) 
(fmap . fmap) 
    :: (Functor f, Functor f1) => (a -> b) -> f1 (f a) -> f1 (f b) 

Prelude> :t (fmap . fmap) sum 
(fmap . fmap) sum 
    :: (Num b, Foldable t, Functor f, Functor f1) => 
    f1 (f (t b)) -> f1 (f b) 

Prelude> :t (fmap . fmap) sum Just 
(fmap . fmap) sum Just :: (Num b, Foldable t) => t b -> Maybe b 

私は最後の出力を導出する方法を理解していません。 (fmap . fmap) sumデータコンストラクタJustを渡すとき、とfの両方をMaybeに置き換えることをコンパイラはどのように知っていますか?私はここで良い答えを得た後、どうやって自分自身を分かったのだろうか?しかし、関数型(->)Maybe上、(そのタイプの問題を有している(fmap . fmap) sum (Just [1,2,3])であろう)MaybeList両方にわたって持ち上げていない

+3

'(fmap。fmap)'で '.'の定義を展開します。その後、単純化する。そして、あなたの 'fmap'の使い方の1つが2番目の引数として関数を取っていることに気づくでしょう... – Carl

+0

[アプリケーションの種類に適用する?](https://stackoverflow.com/questions/47498896/apply-function)の可能な複製-y-maybe-types) –

+1

@FyodorSoikin、その質問はほとんど完全に無関係に見えます。 – dfeuer

答えて

6

特定の回答の仕組みがわからない場合は、前の手順の種類で指定した引数を並べます。

Prelude> :t (fmap . fmap) sum 
(fmap . fmap) sum 
    :: (Functor f, Functor f1, Num b) => f (f1 [b]) -> f (f1 b) 

だから、この仕事のための順で、Justはタイプf (f1 [b])を持っている必要があり、その後、(fmap . fmap) sum Justはタイプf (f1 b)を持っている必要があります。

Just :: (Functor f, Functor f1, Num b) => f (f1 [b]) 

それはここに、その者の代わりにRHSを試してみましょうべきff1明らかではありません。私たちは、カンニングと(fmap . fmap) sum Justの実際の値がどうあるべきかをチェックするためにGHCiのを頼むことができます。

Prelude> :t (fmap . fmap) sum Just 
(fmap . fmap) sum Just :: Num b => [b] -> Maybe b 

しかし、このべき試合:

(Functor f, Functor f1, Num b) => f (f1 b) 

我々はff1が何であるかを把握しようとしていますここに。だから我々はそれが(時々->はシンタックスシュガーであることを覚えていると邪魔になる)と同じ構造を有しているので、それを少し書き換える必要があります:

(fmap . fmap) sum Just :: Num b => [b] -> Maybe b 
-- Same as... 
(fmap . fmap) sum Just :: Num b => (->) [b] (Maybe b) 
-- Or... 
(fmap . fmap) sum Just :: Num b => ((->) [b]) (Maybe b) 
--      Functor f = ((->) [b]) 
--        Functor f1 = Maybe 

だから私たちは順番に型が一致することを把握することができますFunctor f(->) [b]でなければなりません...関数もまた関数であることを覚えておいてください! Functor f1Maybeです。これはもう少し明白です。

Prelude> :t (fmap . fmap) sum :: Num b => ([b] -> Maybe [b]) -> ([b] -> Maybe b) 
(fmap . fmap) sum :: Num b => ([b] -> Maybe [b]) -> ([b] -> Maybe b) 
    :: Num b => ([b] -> Maybe [b]) -> [b] -> Maybe b 

をそしてGHCiのはそれだけで罰金のチェックを入力思う:

我々はこれを試すことができます。

ここで忘れやすいのは、(->) [b]が有効なファンクタです。

+0

最近では、 'sum'がより一般的な型を持っているので、型シグネチャを与えたいかもしれません。 – dfeuer

+0

このような状況では、単に 'Num a => [a] - > a'であり、より一般的な型シグネチャでは物事が変更されません。 –

6

Just :: a -> Maybe a 
    -- ((->) a) (Maybe a) 
    -- f (g a) for f ~ ((->) a) and g ~ Maybe 

(fmap . fmap) :: (a -> b) -> f (g a ) -> f (g b) 
    -- Num x => ([x] -> x) -> f (g [x]) -> f (g x) 
    -- Num x => ([x] -> x) -> ([x] -> Maybe [x]) -> [x] -> Maybe x 
    --  ^   ^     ^
    --   sum   Just     [1,2,3] 
関連する問題