Пары, по сути, определяются следующим образом:
data (,) a b = (,) a b
Класс Functor
выглядит так:
class Functor f where
fmap :: (a -> b) -> f a -> f b
Так как типы аргументов и результатов функций должны иметь вид *
(т.е. они представляют собой значения, а не функции типов, которые можно применять дальше или более экзотические вещи), мы должны иметь a :: *
, b :: *
и, что наиболее важно для наших целей, f :: * -> *
. Поскольку (,)
имеет тип * -> * -> *
, его необходимо применить к типу типа *
, чтобы получить тип, подходящий для Functor
. Таким образом
instance Functor ((,) x) where
-- fmap :: (a -> b) -> (x,a) -> (x,b)
Так что на самом деле нет никакого способа написать экземпляр Functor
, делающий что-то еще.
Один полезный класс, который предлагает больше способов работы с парами, — это Bifunctor
из Data.Bifunctor
.
class Bifunctor f where
bimap :: (a -> b) -> (c -> d) -> f a c -> f b d
bimap f g = first f . second g
first :: (a -> b) -> f a y -> f b y
first f = bimap f id
second :: (c -> d) -> f x c -> f x d
second g = bimap id g
Это позволяет вам писать что-то вроде следующего (из Data.Bifunctor.Join
):
newtype Join p a =
Join { runJoin :: p a a }
instance Bifunctor p => Functor (Join p) where
fmap f = Join . bimap f f . runJoin
Join (,)
тогда по существу совпадает с Pair
, где
data Pair a = Pair a a
Конечно, вы также можете просто использовать экземпляр Bifunctor
для непосредственной работы с парами.
person
dfeuer
schedule
05.01.2016