2 Stimmen

Ich habe Probleme beim Schreiben meiner fmap

Ich versuche, eine fmap für diesen Typ zu schreiben

data Triangle a  = Triangle {t0 :: Point a, t1 ::  Point a, t2 ::  Point a}

wobei Punkt definiert ist als

data Point a = Point {px :: a, py :: a, pz :: a}

Und meine Instanz def ist

instance Functor Triangle where 
    fmap f (Triangle v0 v1 v2) = Triangle (f v0) (f v1) (f v2)

Ich erhalte die folgende Fehlermeldung und kann nicht herausfinden, warum

 C:\\Scripts\\Haskell\\Geometry.hs:88:1:
     Occurs check: cannot construct the infinite type: a = Point a
     When generalising the type(s) for \`fmap'
     In the instance declaration for \`Functor Triangle'

Irgendwelche Ideen?

8voto

sdcvvc Punkte 24933
instance Functor Point where
    fmap f (Point v0 v1 v2) = Point (f v0) (f v1) (f v2)

instance Functor Triangle where
    fmap f (Triangle v0 v1 v2) = Triangle (fmap f v0) (fmap f v1) (fmap f v2)

In der Instanz "Triangle", f ist a -> b . Wir müssen es umwandeln in Point a -> Point b zuerst. Dann können wir fmap f umwandeln Triangle a zu Triangle b . (Beachten Sie, dass Sie die f auf 9 Objekte, wenn ich Ihre Absicht richtig verstanden habe) [edit: war 27]

8voto

Chris Conway Punkte 54023

Die vorherige Antwort gibt Ihnen eine korrekte Lösung, aber es könnte hilfreich sein, genauer zu erklären, was hier vor sich geht. Die Art der fmap ist

fmap :: Functor f => (a -> b) -> f a -> f b

Die Typinferenz für Ihre instance Die Erklärung geht wie folgt vor:

  1. Unter fmap f (Triangle v0 v1 v2) , f muss eine Art von a -> b y (Triangle v0 v1 v2) muss Typ haben Triangle a .
    • Gemäß der Definition von Triangle , v0 , v1 und v2 muss Typ haben Point a .
    • Seit f wird angewendet auf v0 , v1 und v2 sein Argument Typ a muss sein Point a .
    • Ups, a = Point a ist unbefriedigend.

Warum ist die Definition Triangle (fmap f v0) (fmap f v1) (fmap f v2) arbeiten? :

  1. Unter fmap f (Triangle v0 v1 v2) , f muss eine Art von a -> b y (Triangle v0 v1 v2) muss Typ haben Triangle a .
    • Gemäß der Definition von Triangle , v0 , v1 und v2 muss Typ haben Point a .
    • Angenommen, Point ist eine Instanz von Functor wie oben, fmap f v0 muss Typ haben Point b , wobei b ist der Ergebnistyp von f . Gleiches gilt für v1 y v2 .
    • Daher Triangle (fmap f v0) (fmap f v1) (fmap f v2) hat Typ Triangle b .
    • QED.

2voto

yairchu Punkte 21749

Übrigens, eine interessante Eigenschaft von Functor ist, dass es nur einen einzigen möglichen Fall gibt, der die Anforderungen der Funktorengesetze .

Besser noch, diese Instanz kann automatisch für Sie erzeugt werden, indem Sie die ableiten. Paket:

{-# LANGUAGE TemplateHaskell #-}

import Data.DeriveTH (derive, makeFunctor)

data Point a = Point {px :: a, py :: a, pz :: a}
$(derive makeFunctor ''Point)

data Triangle a  = Triangle {t0 :: Point a, t1 ::  Point a, t2 ::  Point a}
$(derive makeFunctor ''Triangle)

Imho ist dies ein Gewinn, denn wenn Sie beschließen, die Definition von Triangle , seine Functor Instanz wird automatisch für Sie gepflegt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X