Jak działa funkcja fmap?

0

Jak działa funkcja fmap? Funkcja map wyjmuje element z listy umożliwia działanie funkcji która jest określona dla innych elementów niżlisty a następnie z powrotem wkłada ten element do listy tak? Jak działa funkcja fmap i dlaczego właściwie jest klasa typu Functor?

1

:O

  1. map tak nie działa.
  2. map tworzy nowa liste na podstawie elementów z poprzedniej listy i funkcji mapującej.
  3. map jest zdefiniowany tak: map = fmap.
  4. fmap to abstrakcja na coś co możesz mapować, dowolną rzecz.
0

Klasa typu functor umożliwia nam zdefiniowanie typu który może być zmapowany? Dobrze rozumiem?

0

No nie. Ona nie umożliwia definiowania typów. Typ, który może być mapowany definiujesz jak chcesz. Jeśli Twój typ będzie instancją klasy Functor, to możesz po prostu korzystać z funkcji, które na tym polegają. Typeclassy to tak jak interfejsy w językach obiektowych, tylko trochę bardziej potężne.

1

Fuktor jest czysto abstrakcyjny i określony tylko i wyłącznie przez prawa. Prawa te są opisane np na: https://wiki.haskell.org/Functor (tuż pod all instances of functor should obey).
Prawa, które musi spełniać funktor są jedyną cechą wspólną wszystkich funktorów. Wszelkie intuicje, które wychodzą ponad to są błędne.

Można zdefiniować instancję funktora dla parsera, generatora, listy, typu Either, samych funkcji, monady State itd

Funktor może być nawet zupełnie bez sensu, ale będzie funktorem o ile będzie spełniał wspomniane prawa.

1

@n0name_l
Jaki byłby sens tworzenia teorii z wykorzystaniem oszukanego funktora? Dam przykład w Scali:

import scala.language.higherKinds
import scala.util.Random
 
object Main {
  case class MyType[A](value: List[A])
 
  trait Functor[F[_]] {
    def map[A, B](fa: F[A])(f: A => B): F[B]
  }
 
  val myFunctor: Functor[MyType] = new Functor[MyType] {
    val random = new Random()
 
    override def map[A, B](fa: MyType[A])(f: A => B): MyType[B] =
      MyType(fa.value.flatMap(a =>
        List.fill(choose)(refine(f(a)).asInstanceOf[B])))
 
    private def choose = random.nextInt(5)
 
    private def refine(x: Any): Any = x match {
      case 5 => 8
      case _ => x
    }
  }
 
  def main(args: Array[String]) {
    val m = myFunctor
 
    val fa = MyType(List(1, 2, 3))
    println(m.map(fa)(i => i + 2))
    println(m.map(fa)(i => i + 2))
    println(m.map(fa)(i => i + 2))
    println(m.map(fa)(i => i + 2))
    println(m.map(fa)(i => i + 2))
    println(m.map(fa)(i => i + 2))
  }
}

Wynik z http://ideone.com/vN4sQ2

MyType(List(3, 3, 3, 8))
MyType(List(3, 3, 4, 4, 4, 8))
MyType(List(3, 3, 3, 3, 4, 8, 8, 8, 8))
MyType(List(3, 3, 4, 8, 8, 8))
MyType(List(3, 3, 3, 3, 4, 8, 8, 8, 8))
MyType(List(3, 8, 8, 8, 8))

Funktor jest niedeterministyczny (random) i modyfikuje wyniki funkcji (refine). Nie spełnia żadnego kontraktu oprócz zgodności typów (w zasadzie to utrzymuje kontrakt funktora jeśli zawęzimy się do pustych list, ale kontrakt ma działać dla całej dziedziny; na pustych listach i tak nic nie podziałamy). Budowanie funkcji z jego użyciem nie ma sensu, bo nie będą spełniać żadnych sensownych kontraktów.

1 użytkowników online, w tym zalogowanych: 0, gości: 1