Sie möchten Funktionen heben vom Typ Integer -> Integer -> Integer
bis Foo -> Foo -> Foo
. Um dies zu tun könnten Sie Utility-Funktionen definieren:
liftFoo :: (Integer -> Integer) -> Foo -> Foo
liftFoo f (Foo a) = Foo $ f a
liftFoo2 :: (Integer -> Integer -> Integer) -> Foo -> Foo -> Foo
liftFoo2 f (Foo a) (Foo b) = Foo $ f a b
-- and so on
Dann könnten Sie es wie folgt verwenden:
liftFoo2 (+) (Foo 10) (Foo 5)
liftFoo2 max (Foo 10) (Foo 5)
Dies hat den Vorteil, keine Verlängerung erforderlich ist.
Eine weitere Option ist die Definition des Foo
newtype mehr zulässig zu machen, so dass Sie es eine Instanz von Functor
und Applicative
machen könnte:
:
import Control.Applicative
newtype Foo a = Foo a deriving (Eq, Show)
foo :: Integer -> Foo Integer
foo = Foo
instance Functor Foo where
fmap f (Foo a) = Foo $ f a
instance Applicative Foo where
pure = Foo
(Foo f) <*> (Foo a) = Foo $ f a
Nun könnte man folgendes tun
(+) <$> foo 10 <*> foo 5
max <$> foo 10 <*> foo 5
Da foo
auf den Integer
Typ spezialisiert ist, verlieren Sie keine Vorteile der Typprüfung.
Wird diese Technik als idiomatisch angesehen? –
@KevinMeredith Ja, es ist idiomatisch. Aber nur zu deiner eigenen Erleuchtung solltest du versuchen, die "Ord" und "Num" Instanzen selbst zu schreiben. – augustss