Learn you a Haskell For Great Good という本と、カテゴリ オブジェクトとプログラミング オブジェクトを混同するというよくあるカテゴリの誤りを克服するのに役立つ非常に役立つウィキ ブックの記事Haskell カテゴリ理論を読んだ後、私はまだ次の疑問を持っています。
fmap
リストのすべての要素をマップする必要があるのはなぜですか?
私はそれが好きです、これが理論的にどのように正当化されたカテゴリであるかを理解したいだけです. (または、HoTT を使用する方が簡単に正当化できるのでしょうか?)
Scala表記でList
は、任意の型を取り、それをすべてのリスト型のセットから型にマップするファンクタです。たとえば、型Int
を型List[Int]
にマップし、関数をInt
たとえば
Int.successor: Int => Int
にFunctor[List].fmap(successor) : List[Int] => List[Int]
Int.toString: Int => String
にFunctor[List].fmap(toString): List[Int] => List[String]
現在、 のすべてのインスタンスは、関数( Haskell の場合) と関数( Haskell の場合) をList[X]
持つモノイドです。私の推測では、リストがモノイドであるという事実を使用して、リストのすべての要素をマップする必要があることを示すことができます。ここで私が感じているのは、Applicative から関数を追加すると、他のタイプの要素が 1 つだけのリストが得られるということです。例えば。これらの要素では、次の要素を含むシングルトン リストが得られるため、これですべてのサブセットがカバーされます。次に、これらすべてのシングルトンの関数が、リストの他のすべての要素を提供すると思います。どういうわけか、それがマップの動作方法を制限していると思います。empty
mempty
combine
mappend
map
pure
Applicative[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)