11

Learn you a Haskell For Great Good という本と、カテゴリ オブジェクトとプログラミング オブジェクトを混同するというよくあるカテゴリの誤りを克服するのに役立つ非常に役立つウィキ ブックの記事Haskell カテゴリ理論を読んだ後、私はまだ次の疑問を持っています。

fmapリストのすべての要素をマップする必要があるのはなぜですか?

私はそれが好きです、これが理論的にどのように正当化されたカテゴリであるかを理解したいだけです. (または、HoTT を使用する方が簡単に正当化できるのでしょうか?)

Scala表記でListは、任意の型を取り、それをすべてのリスト型のセットから型にマップするファンクタです。たとえば、型Intを型List[Int]にマップし、関数をIntたとえば

  • Int.successor: Int => IntFunctor[List].fmap(successor) : List[Int] => List[Int]
  • Int.toString: Int => StringFunctor[List].fmap(toString): List[Int] => List[String]

現在、 のすべてのインスタンスは、関数( Haskell の場合) と関数( Haskell の場合) をList[X]持つモノイドです。私の推測では、リストがモノイドであるという事実を使用して、リストのすべての要素をマップする必要があることを示すことができます。ここで私が感じているのは、Applicative から関数を追加すると、他のタイプの要素が 1 つだけのリストが得られるということです。例えば。これらの要素では、次の要素を含むシングルトン リストが得られるため、これですべてのサブセットがカバーされます。次に、これらすべてのシングルトンの関数が、リストの他のすべての要素を提供すると思います。どういうわけか、それがマップの動作方法を制限していると思います。emptymemptycombinemappendmappureApplicative[List[Int]].pure(1) == List(1)map(succ)combine

別の示唆的な議論は、mapリスト間で関数をマップする必要があるというものです。a のすべての要素はList[Int]Int 型であるため、1 つを 1 つList[String]にマップする場合、そのすべての要素をマップする必要があります。そうしないと、適切な型ではありません。

したがって、これらの議論はどちらも正しい方向を指しているように見えます。しかし、私は残りの道を得るために何が必要なのか疑問に思っていました.

反例?

これが反例写像関数ではないのはなぜですか?

def map[X,Y](f: X=>Y)(l: List[X]): List[Y] = l match {
  case Nil => Nil
  case head::tail=> List(f(head))
}

ルールを守っているようです

val l1 = List(3,2,1)
val l2 = List(2,10,100)

val plus2 = (x: Int) => x+ 2
val plus5 = (x: Int) => x+5

map(plus2)(List()) == List()
map(plus2)(l1) == List(5)
map(plus5)(l1) == List(8)

map(plus2 compose plus5)(l1) == List(10)
(map(plus2)_ compose map(plus5)_)(l1) == List(10)

ああ。しかし、それはid法に適合しません。

def id[X](x: X): X = x

map(id[Int] _)(l1) == List(3)
id(l1) == List(3,2,1)
4

1 に答える 1

11

これは、最初にレイノルズによって定義され、次にワドラーによって開発された「パラメトリック性」と呼ばれる理論的結果に依存しています。おそらく、このトピックに関する最も有名な論文は「Theorems for free!」です。ワドラーによる。

重要なアイデアは、関数の多相型のみから、関数のセマンティクスに関する情報を取得できるということです。例えば:

foo :: a -> a

fooこのタイプだけから、終了する場合、それは恒等関数であることがわかります。直観的にfooは、異なる を区別することはできません。Haskell には、実際のランタイム タイプを検査できるaJava などがないためです。instanceof同様に、

bar :: a -> b -> a

最初の引数を返す必要があります。またbaz :: a -> a -> a、最初または 2 番目のいずれかを返す必要があります。そしてquz :: a -> (a -> a) -> a、関数を最初の引数に一定回数適用する必要があります。あなたはおそらく今考えを得るでしょう。

型から推測できる一般的なプロパティは非常に複雑ですが、幸いにも機械的に計算できます。圏論では、これは自然変換の概念に関連しています。

タイプについてはmap、次の恐ろしいプロパティを取得します。

forall t1,t2 in TYPES, f :: t1 -> t2.
 forall t3,t4 in TYPES, g :: t3 -> t4.
  forall p :: t1 -> t3.
   forall q :: t2 -> t4.
    (forall x :: t1. g (p x) = q (f x))
    ==> (forall y :: [t1].
          map_{t3}_{t4} g (map2_{t1}_{t3} p y) =
          map2_{t2}_{t4} q (map_{t1}_{t2} f y))

上記のmapはよく知られている map 関数ですが、map2は type を持つ任意の関数(a -> b) -> [a] -> [b]です。

map2ここで、が関手法則、特にを満たすとさらに仮定しmap2 id = idます。次に、p = idとを選択できますt3 = t1。我々が得る

forall t1,t2 in TYPES, f :: t1 -> t2.
 forall t4 in TYPES, g :: t1 -> t4.
   forall q :: t2 -> t4.
    (forall x :: t1. g x = q (f x))
    ==> (forall y :: [t1].
          map_{t1}_{t4} g (map2_{t1}_{t1} id y) =
          map2_{t2}_{t4} q (map_{t1}_{t2} f y))

に関手法則を適用するmap2

forall t1,t2 in TYPES, f :: t1 -> t2.
 forall t4 in TYPES, g :: t1 -> t4.
   forall q :: t2 -> t4.
    (forall x :: t1. g x = q (f x))
    ==> (forall y :: [t1].
          map_{t1}_{t4} g y =
          map2_{t2}_{t4} q (map_{t1}_{t2} f y))

t2 = t1それでは、選択してみましょうf = id

forall t1 in TYPES.
 forall t4 in TYPES, g :: t1 -> t4.
   forall q :: t1 -> t4.
    (forall x :: t1. g x = q x)
    ==> (forall y :: [t1].
          map_{t1}_{t4} g y =
          map2_{t1}_{t4} q (map_{t1}_{t1} id y))

の関手法則によりmap

forall t1, t4 in TYPES.
   forall g :: t1 -> t4, q :: t1 -> t4.
    g = q
    ==> (forall y :: [t1].
          map_{t1}_{t4} g y =
          map2_{t1}_{t4} q y)

つまり

forall t1, t4 in TYPES.
 forall g :: t1 -> t4.
    (forall y :: [t1].
          map_{t1}_{t4} g y =
          map2_{t1}_{t4} g y)

つまり

forall t1, t4 in TYPES.
          map_{t1}_{t4} = map2_{t1}_{t4}

要約:

map2多相型(a -> b) -> [a] -> [b]を持ち、第 1 関手の法則 を満たすようなmap2 id = id関数である場合map2、標準map関数と等価でなければなりません。

Edward Kmett による関連ブログ投稿も参照してください。

x.isInstanceOf[]Scala では、パラメトリック性を壊す可能性のある やその他のリフレクション ツールを使用しない場合にのみ上記が当てはまることに注意してください。

于 2016-04-19T11:08:28.570 に答える