Я написал newtype Const3
, который очень похож на Const
, но содержит первый из трех заданных аргументов типа:
newtype Const3 a b c = Const3 { getConst3 :: a }
Я могу определить очень много полезных экземпляров для этого нового типа, но я должен был бы все это сделать сам.
Однако функция, которую я применяю на уровне типа, похожа на функцию
\a b c -> a
который @pl
говорит мне, эквивалентен const . const
.
Оба (.)
и Const
имеют соответствующие оболочки newtype: Compose
и Const
. Поэтому я решил, что смогу написать:
type Const3 = Compose Const Const
И наследуйте полезные экземпляры автоматически, например:
instance Functor (Const m)
instance (Functor f, Functor g) => Functor (Compose f g)
-- a free Functor instance for Const3!
Но GHC не согласен:
const3.hs:5:23:
Expecting one more argument to ‘Const’
The first argument of ‘Compose’ should have kind ‘* -> *’,
but ‘Const’ has kind ‘* -> * -> *’
In the type ‘Compose Const Const’
In the type declaration for ‘Const3’
Это, по-видимому, связано с типами Compose
и Const
:
*Main> :k Compose
Compose :: (* -> *) -> (* -> *) -> * -> *
*Main> :k Const
Const :: * -> * -> *
Итак, после небольшого поиска я обнаружил, что расширение GHC под названием PolyKinds
, которое позволяет мне делать что-то вроде:
{-# LANGUAGE PolyKinds #-}
newtype Compose f g a = Compose { getCompose :: f (g a) }
newtype Const a b = Const { getConst :: a }
И, как по волшебству, все правильно:
*Main> :k Compose
Compose :: (k -> *) -> (k1 -> k) -> k1 -> *
*Main> :k Const
Const :: * -> k -> *
Но я все еще не могу написать им писать Const3 = Compose Const Const
.
const3.hs:12:23:
Expecting one more argument to ‘Const’
The first argument of ‘Compose’ should have kind ‘* -> *’,
but ‘Const’ has kind ‘* -> k0 -> *’
In the type ‘Compose Const Const’
In the type declaration for ‘Const3’
Что дает? Есть ли какой-нибудь умный способ сделать это, поэтому я могу воспользоваться преимуществами наследования экземпляров Functor
etc от Const
и Compose
?
(Как примечание, оригинальная мысль, которая привела меня к
Const3
, писала:newtype Const3 a b c = Const3 { getConst3 :: a } instance Monoid m => Category (Const3 m) where id = Const3 mempty Const3 x . Const3 y = Const3 (mappend x y)
захват идеи о том, что моноид - это категория одного объекта. Было бы неплохо, если бы было решение, которое все еще позволяет мне как-то написать вышеприведенный экземпляр.)