Bạn muốn nhấc chức năng của loại Integer -> Integer -> Integer
đến Foo -> Foo -> Foo
. Để làm như vậy bạn có thể xác định các chức năng tiện ích:
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
Sau đó, bạn có thể sử dụng nó như sau:
liftFoo2 (+) (Foo 10) (Foo 5)
liftFoo2 max (Foo 10) (Foo 5)
này có lợi thế là không đòi hỏi một phần mở rộng.
Một lựa chọn khác là làm cho định nghĩa của Foo
Newtype phép nhiều hơn như vậy mà bạn có thể làm cho nó một thể hiện của Functor
và 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
Bây giờ bạn có thể làm như sau:
(+) <$> foo 10 <*> foo 5
max <$> foo 10 <*> foo 5
Vì foo
chuyên loại Integer
bạn không mất bất kỳ lợi ích của việc kiểm tra loại.
Nguồn
2014-10-06 03:43:40
Sử dụng kỹ thuật này có được coi là thành ngữ không? –
@KevinMeredith Vâng, nó là thành ngữ. Nhưng chỉ cho giác ngộ của riêng bạn, bạn nên thử viết bản thân 'Ord' và' Num'. – augustss