2016-05-31 1 views
2

私はタイプを使用してこれを通過しようとしましたが、私はまだそれがどのように動作するのか理解するのが難しいです。リストが(==)<*>逆を使用している回文索引かどうかを調べることができます。どのように機能するのですか?

考える:

> :t (==) 
(==) :: Eq a => a -> a -> Bool 

> :t (<*>) 
(<*>) :: Applicative f => f (a -> b) -> f a -> f b 

> :t reverse 
reverse :: [a] -> [a] 

> :t (==) <*> reverse 
(==) <*> reverse :: Eq a => [a] -> Bool 

直感的に、私はそれはそれは逆リストが元に等しいかどうかを確認する関数を作成するように、逆と等価演算子を組み合わせたことを理解することができますが、それは本当にありません既にかなり明白なものよりはるかに多くの情報を提供します。

ここで実際に起こっている事柄について、誰かが内部の詳細を細分することができますか?

答えて

2

クリス・テイラーの答えはちょうどいいですが、それを見て別の方法、私はより直感的に見つけること、これである:同じ

  1. 「フィード」:どのような関数型のApplicativeインスタンスがないことはこれです同じ引数型を持つ2つの関数への引数値。
  2. その結果を別の関数と組み合わせます。

あなたはf :: t -> ag:: t -> bを持っているのであれば基本的には、Applicativeインスタンスは、あなたがfgは同じ引数を供給することになるという仮定の下で、ab結果オーバー機能h :: a -> b -> cをマッピングすることができます。

ですから、非複雑な方法で回文テストを書きたいかを考える:

palindrome :: Eq a => [a] -> Bool 
palindrome xs = xs == reverse xs 

xsは、定義の右側に2回表示:一度==への引数、第二として、時間はreverseの引き数になります。これにより、アプリケーションインスタンス(->) tを使用して重複を排除する方法があることが自動的に伝えられます。

palindrome xs = id xs == reverse xs 

... id x = xはちょうどその引数を返します(標準ライブラリ関数である恒等関数、次のとおりです。この上の異なる、おそらくより直感的な攻撃は、最初にこのする機能を書き換えることであろう)。

-- Function that feed the same argument value to both `id` and `reverse`, 
-- then tests their results with `==`: 
palindrome = (==) <$> id <*> reverse 

をそして、その書き換えにidを取り除く方法がある場合、今、私たちは尋ねることができます:今、あなたは、これに標準Applicativeイディオム(f <$> a0 <*> ... <*> an)を使用していることを書き換えることができます。 <$>fmapのためだけの省略形ですので、我々は関数合成を表現するもうひとつの方法である、(->) tためFunctorインスタンスを学ぶことができます。

instance Functor ((->) t) where 
    -- Mapping `f` over a *function* `g` is just the same as composing `f` 
    -- on the results of `g`. 
    fmap f g = f . g 

機能組成物の最も重要な特性の1つは、任意の関数fのためということです。

f . id = f 

したがって、上記のpalindromeのバージョンにそれを適用し、我々が得る:

-- Since `f . id = f` for all `f`, then `(==) <$> id` is just `(==)`: 
palindrome = (==) <*> reverse 
+0

どうしてあなたはいつもきれいで分かりやすい答えを出さなければならないのですか? – dfeuer

+0

2ヶ月後にそれに戻ってくることははるかに理にかなっています。ありがとう! – m0meni

7

(<*>)

> : t (<*>) 
(<*>) :: Applicative f => f (a -> b) -> f a -> f b 

のタイプのスタートすぐ(->) k特に実装

instance Applicative ((->) k) where 
    pure a = \_ -> a 
    f <*> g = \k -> f k (g k) 

と、(->) kに特化(<*>)のタイプは

(<*>) :: (k -> a -> b) -> (k -> a) -> (k -> b) 
ある、 Applicativeのインスタンスであります

だからアプリケーション(==) <*> reverseは、リストは、その逆に等しいことを確認

(==) <*> reverse = \k -> (==) k (reverse k) 
       = \k -> k == reverse k 

すなわちあります。

+0

'( - >)kは何を意味するのですか?ラムダですか? – m0meni

+2

背景: '(( - >)t)'は '' tを入力とする関数で、 't'は' String'です。そのためのApplicativeインスタンスは 'String'を受け取り、それを最初の関数' f'に渡し、別の関数 'f''を返します。同じ文字列*を2番目の関数に渡し、ある種の値を返す。返り値で 'f 'を呼び出します。したがって、 '(f <*> g)x == f x(g x)'となる。 – amalloy

+0

@amalloy「<*>」のタイプシグネチャがどのように変更されるのか、多くの混乱があると思います。例えば、 'f(a - > b)'が '(k - > a - > b)'になった例です。なぜこれは '( - >)k'の場合ですか? – m0meni

関連する問題