Chcesz podnieść funkcje typu Integer -> Integer -> Integer
do Foo -> Foo -> Foo
. Aby to zrobić można definiować funkcje użytkowe:
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
Następnie można go używać w następujący sposób:
liftFoo2 (+) (Foo 10) (Foo 5)
liftFoo2 max (Foo 10) (Foo 5)
Ma to tę zaletę, że nie wymaga rozszerzenia.
Inną opcją jest, aby definicja Foo
newtype bardziej dopuszczalne tak, że można zrobić to wystąpienie Functor
i Applicative
:
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
Teraz można wykonać następujące czynności:
(+) <$> foo 10 <*> foo 5
max <$> foo 10 <*> foo 5
Ponieważ foo
specjalizuje się w typie Integer
, nie tracisz korzyści z kontroli typu.
Czy ta technika jest uważana za idiomatyczną? –
@KevinMeredith Tak, jest to idiomatyczne. Ale dla własnego oświecenia powinieneś sam spróbować napisać instancje 'Ord' i' Num'. – augustss