8

関数の理由を理解しようとしています

map (filter fst)

タイプを持っています

[[(Bool, a)]] -> [[(Bool, a)]]

フィルターがブール型を返す関数を受け取る必要があり、fst がタプルの最初の要素を返すだけの場合、「フィルター fst」はどのように機能しますか?

filter :: (a -> Bool) -> [a] -> [a]
fst :: (a, b) -> a

誰でも私を説明できますか?ありがとう ;)

4

6 に答える 6

17

フィルターがブール型を返す関数を受け取る必要があり、fst がタプルの最初の要素を返すだけの場合、「フィルター fst」はどのように機能しますか?

ある意味で、あなたはあなた自身の質問に答えました! それを分解しましょう:

フィルタは Bool-Type を返す関数を受け取る必要があります

では、何を渡すか見てみましょう: fst. fst関数ですか?はい、そうです。最初の部分を下に置きました。を返しBoolますか?さて、それが何をするか見てみましょう:

fst はタプルの最初の要素を返すだけです

したがって、タプルの最初の要素が a の場合Bool、はい、bool を返します! ただし、タプルの最初の要素が a 以外のBool場合、型チェックは失敗し、失敗します。

あなたが立てたタイプをもう一度見てみましょう。わかりやすくするために、型変数の名前を変更します。

filter :: (a -> Bool) -> [a] -> [a]
fst :: (b, c) -> b

fstを取り、(b, c)を返します。フィルタは、 を取り、を返すb関数を期待しています。を渡しているので、上記はの最初のパラメーターである必要があります。渡す関数の戻り値はa でなければならないため、上記は aでなければなりません。フィルターではまったく使用されないため、何でもかまいません。との値を代入すると、 ofの最終的な型が得られます。aBoolfsta(b, c)fstfilterBoolbBoolcabfilter fst

filter fst :: [(Bool, c)] -> [(Bool, c)]

最後に、のタイプmapは次のとおりです。

map :: (d -> e) -> [d] -> [e]

(繰り返しますが、ここで型変数の名前を変更しました。これは、上記で使用したものと区別するためですが、型変数のスコープ内で一貫している限り、それらが何と呼ばれているかは実際には問題ではないことを覚えておいてください。型注釈)

map (filter fst)filter fst上で定義した を最初のパラメータとして に渡しますmap。のパラメータdと の結果を置き換えると、eこの関数は でなければならない[(Bool, c)] -> [(Bool, c)]、つまりdとの両方eがであることがわかります(Bool, c)。それらを関数にプラグインすると、最終的な型に到達します。

map (filter fst) :: [[(Bool, c)]] -> [[(Bool, c)]]
于 2014-03-19T12:08:19.627 に答える
2

fstタプルを最初の要素としてブール値を持つように制限する限り、ブール値を返す関数です (2 番目の要素は何でもかまいません。したがって、(Bool, a)

于 2014-03-19T11:58:51.930 に答える
1
:t filter    -- (a -> Bool) -> [a] -> [a]
:t fst       -- (a,b) -> a

ただし、型変数を交換しfstて取得することもできます。

:t fst       -- (c,b) -> c

したがって、 の最初の引数filterは typeですがa -> Boolfstそれ自体は(c,b) -> cです。今、これを結合しようとしています (これは統合と呼ばれていると思います):

1st arg of filter:  a     -> Bool
fst:                (c,b) -> c

このことから、(右辺が等しくcなければならないため) である必要があると推測し、次を取得できます。Bool

1st arg of filter:  a        -> Bool
fst:                (Bool,b) -> Bool

a上記から、 である必要があると推測し(Bool,b)、以下を取得します。

1st arg of filter:  (Bool,b) -> Bool
fst:                (Bool,b) -> Bool

これで完了です。

于 2014-03-19T11:59:36.257 に答える
1

他の人が行ったように、ここで型方程式を解きたいと思います。しかし、より視覚的な方法でそれらを書き留めたいので、導出はより自動化された方法で実行できます。どれどれ。

filter :: (  a   -> Bool) -> [a] -> [a]
fst    ::  (c,d) -> c              -- always use unique type var names, 
------------------------           --   rename freely but consistently
filter fst :: [a] -> [a],    a -> Bool  ~  (c,d) -> c
                             a ~ (c,d)  ,  Bool ~ c
                             a ~ (Bool,d)
           ---------------------------
           :: [(Bool,d)] -> [(Bool,d)]

純粋に機械的なもの。:) これとともに、

map        :: (     a     ->     b     ) -> [a] -> [b]
filter fst ::  [(Bool,d)] -> [(Bool,d)]
------------------------------
map (filter fst) :: [a] -> [b],     a ~ [(Bool,d)]  ,  b ~ [(Bool,d)]
                 -------------------------------
                 :: [[(Bool,d)]] -> [[(Bool,d)]]

最終的な型の型変数は、読みやすくするために (もちろん一貫した方法で) 自由に名前を変更できます。

ここでの他の回答ですでに示されているものに私の回答が追加する唯一のことは、このアドバイスです(これは重要だと思います):あるものを他のものの下に書き留めるというこの単純な規律に従うと、これらのタイプを実行するのが非常に簡単になります非常に機械的で自動的な方法での統合 (したがって、エラーの可能性を減らします)。

実際の型派生 Prolog プログラムを含むこの別の例については、Haskell: how to infer the type of an expression manual を参照してください。

于 2014-03-20T15:43:59.627 に答える
1

ダニエルプライトの回答が投稿される前にこれを書き留めたので、とにかく投稿します。ここのタイプの思考プロセスをたどっていfilter fstます。

まず、型シグネチャを書き留めます (その型変数名がフィルターのものと衝突しないように fst を変更します):

filter :: (a -> Bool) -> [a] -> [a]
fst :: (b, c) -> b

(a -> Bool)と一致((b, c) -> b):

bでなければならないBool、つまり、そうでaなければならない(Bool,c)

この情報に特化するfilterと、次のようになります。

filter :: ((Bool,c) -> Bool) -> [(Bool,c)] -> [(Bool,c)]

につながる

filter fst :: [(Bool, c)] -> [(Bool, c)]
于 2014-03-19T12:14:42.197 に答える