2016-06-20 11 views
5

Wir wissen, dass jeder generische Typ F[_] mit map Methode, die einigen entspricht, ein Funktor ist. Zum Beispiel sind List[_], Option[_] und F[A] = Env => A Funktoren. Ich frage mich nur, ob diese Funktor-Abstraktion sinnvoll ist.Wie sind Funktoren nützlich?

Wie kann ich die Tatsache verwenden, dass sie Funktoren sind? Könnten Sie ein Beispiel für eine nicht-triviale Berechnung zeigen, die die map verwendet und tatsächlich nützlich ist?

+1

Check out http://www.cis.upenn.edu/~cis194/spring13/lectures/09-functors.html –

+0

Auch http://eed3si9n.com/learning-scalaz/Functor.html Was halten Sie für nicht-triviale Berechnung? –

+2

Ich denke, manche Leute interpretieren Michaels Frage falsch. Ich lese es so: Er versteht, dass Funktoren über die 'map()' Methoden einer Vielzahl von verschiedenen Datentypen abstrahieren, aber es fällt ihm schwer zu verstehen, wie man diese Tatsache * nutzen * könnte. Es ist leicht, an Kontexte zu denken, in denen * bestimmte Typen *, die Funktoren sind, angezeigt werden und warum Sie diese Typen in diesen Kontexten * * map() 'haben. Es ist schwieriger, an Kontexte zu denken, in denen Sie eine * type-Variable * verwenden, die auf 'Functor' beschränkt ist, aber keine andere Einschränkung hat! –

Antwort

8

Einer der größten Vorteile von Konzepten wie Funktionen interessiert ist, dass es generische Konstruktionen, die Sie komplexere Arten von einfacher functors erlauben zu bauen, und gewährleisten, dass diese Komplexe Typen haben bestimmte Eigenschaften. Funktoren erscheinen verständlicherweise ziemlich sinnlos, wenn Sie sie isoliert betrachten, wie Sie es getan haben, aber sie werden immer nützlicher, je mehr solche Konstruktionen Sie lernen und beherrschen.

Eines der einfacheren Beispiele ist, dass mehrere Arten der Kombination von Funktoren auch einen Funktor ergeben; zB wenn List[A] und Option[A] functors sind, so sind:

  • Zusammensetzung der functors:List[Option[A]] und Option[List[A]]
  • Produkte von functors:(List[A], Option[A])
  • Sums von functors:Either[List[A], Option[A]]

Ich weiß nicht w genug, um dies in Scala zu schreiben, aber in Haskell Tatsachen wie diese in generische Codes wie diese Beispiele übersetzen:

-- A generic type to represent the composition of any two functors 
-- `f` and `g`. 
newtype Compose f g a = Compose { getCompose :: f (g a) } 

-- If `f` and `g` are functors, so is `Compose f g`. 
instance (Functor f, Functor g) => Functor (Compose f g) where 
    fmap f (Compose fga) = Compose (fmap (fmap f) fga) 

ein sehr einfaches Beispiel Dies ist aber:

  • Es ist schon nützlich als ein analytisches Werkzeug mindestens. Ein Los von Datentypen, die Menschen in der Praxis schreiben, wenn Sie sie durch die Linse dieses Beispiels betrachten, entpuppen sich als Produkte, Summen oder Kompositionen einfacherer Funktoren. Wenn Sie diese Konstruktionen einmal verstanden haben, können Sie automatisch "spüren", wenn Sie einen komplexen Typ schreiben, der ein Funktor ist, und wie er seine map() Operation schreibt.
  • Die aufwändigere Beispiele haben den gleichen Geschmack:
    • Wir haben eine generische Konstruktion, die bestimmte Verträge garantiert, wenn sie mit einer Art instanziiert, die Functor implementiert;
    • Wenn wir einem beliebigen Typ eine Functor Implementierung hinzufügen, können wir diesen Typ in dieser Konstruktion verwenden.

Ein aufwendigeres Beispiel ist free monads (Link ein erweiterte Scala Beispiel hat), eine generische Interpreter Konstruktion, dass die „Anweisungen“ für die Sprache zu definieren, die auf vom Benutzer gelieferten Functor s beruht. Weitere Links (und diese sind meist direkt aus einer Google-Suche):

+0

Danke, Luis. Sehr interessant in der Tat. Können Sie ein Beispiel für eine Berechnung geben, die nur einen 'Functor' verwendet (abgesehen von freien Monaden)? – Michael

1

Nun, wenn Sie wissen, was ein Functor ist, Sie nicht nur map erhalten, erhalten Sie alle Funktionen können Sie mit ihm ableiten zu

Zum Beispiel ist es möglich, die Funktion lift in a abzuleiten So funktioniert das für jeden Funktor.

Aufzug wird „Lift“ eine Funktion A => B-F[A] => F[B] für einige Functor F[_] und wird als

def lift[A, B](f: A => B): F[A] => F[B] = map(_)(f) 

definiert Wenn Sie eine Bibliothek wie cats oder scalaz verwenden, dann erhalten Sie diese kostenlos Funktionen. Die cats documentation hat ein paar andere Beispiele, die Sie vielleicht in

+2

Ich stimme nicht zu, aber ich bin mir nicht sicher, dass dies wirklich die Frage beantwortet. Meiner Erfahrung nach ist es ziemlich selten, dass man im Anwendungscode nur eine "Funktor" -Einschränkung hat - wenn man nur weiß, dass "F" ein Funktor ist, dann muss man ziemlich genau eine Signatur wie 'F [A] = haben > F [B] ', und an diesem Punkt sollten Sie einfach ein' A => B 'definieren und auf der Aufrufseite mappen, wo' F 'oft konkret wird oder andere Fakten darüber bekannt sind. –

6

Ich weiß nicht, Scala, aber in Haskell, die Functor Klasse ist wesentlich für die Definition Van Laarhoven-style lenses :

type Lens' s a = forall f . Functor f => (a -> f a) -> s -> f s 

Diese Objektive sind normalerweise für speziell verwandte Typen definiert s und a, aber es ist wichtig für ihr Dienstprogramm, dass sie mit einem beliebigen Funktor arbeiten.

Functor ist auch in seiner Rolle als eine Oberklasse von Applicative und von Traversable wichtig. Wenn Sie mit diesen leistungsstärkeren Abstraktionen arbeiten, ist es oft sehr nützlich, nach der Methode fmap zu suchen.