我是否可以将这种新类型实现为其他类型的组合?
我写了一个与Const
类似的新类型Const3
,但包含三个给定类型参数中的第一个:
newtype Const3 a b c = Const3 { getConst3 :: a }
我可以为这种新类型定义很多有用的实例,但我必须自己完成。
但是,我在类型级别上应用的函数类似于函数
a b c -> a
@pl
告诉我等价于const . const
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 :: * -> * -> *
所以经过一番搜索之后,我发现有一个称为PolyKinds
的GHC扩展,它允许我执行如下操作:
{-# 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’
是什么赋予了? 有没有一些聪明的方法来做到这一点,所以我可以从Const
和Compose
获得继承Functor
等实例的好处?
(作为一个侧面说明,导致我进入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)
捕捉幺半群是单个对象类别的想法。 如果有一个解决方案仍然允许我以某种方式编写上述实例,那将会很好。)
令人困惑的事情 - 或者至少让我困惑的事情 - 就是*
表现为具体类型,而不是类型变量。 因此,如果没有PolyKinds
, Compose
的类型更像是:
compose :: (A -> A) -> (A -> A) -> A -> A
至关重要的是,我们不能用A -> A
代替A
,因为它们会是不同的类型,所以,通过相同的逻辑,我们不能用* -> *
代替*
。
即使与PolyKinds
,种类仍然不正确。 特别是, Compose
期望(k -> *)
作为它的第一个参数,并且您正试图给它(k -> (k2 -> *))
。
你被迫返回*
种类的原因是因为你使用的是newtypes
,newtypes必须返回一个具体的类型(即kind *
)。 我试图通过将Compose
变成一个类型同义词来克服这个问题,它最终具有我们想要的类型(与PolyKinds
):
type Compose f g a = (f (g a))
λ> :k Compose
Compose :: (k1 -> k) -> (k2 -> k1) -> k2 -> k
然而,使用这仍然给了我一个类似的错误,我不确定我们是否能够正常工作。 问题出现了,因为将Compose
应用到第一个Const
给了我们一个带有*
的类型,可能是因为限制了类型别名,例如:
λ> :k Compose Const
Compose Const :: (k -> *) -> k -> k1 -> *
从其他答案看来,它似乎并不那么容易,但是如果你想要的唯一的东西是“免费”的实例,一个快速的方法是在GeneralizedNewtypeDeriving
扩展中对常规Const
使用newtype
:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE PatternSynonyms #-}
module ConstThree (Const3,pattern Const3,getConst3) where
import Data.Foldable
import Data.Traversable
import Control.Applicative
import Data.Monoid
newtype Const3 a b c = MkConst3 (Const a c) deriving (Functor,Applicative,Foldable,Traversable,Eq,Ord,Show,Monoid)
pattern Const3 :: a -> Const3 a b c
pattern Const3 x = MkConst3 (Const x)
getConst3 :: Const3 a b c -> a
getConst3 (Const3 x) = x
在上面,我也使用PatternSynonyms
来隐藏客户端对Const
的内部使用。
这就是你得到的:
λ> :t Const3
Const3 :: a -> Const3 a b c
λ> :t getConst3
getConst3 :: Const3 a b c -> a
λ> :i Const3
pattern Const3 :: a -> Const3 a b c
-- Defined at /tmp/alpha-dbcdf.hs:13:5
type role Const3 representational phantom phantom
newtype Const3 a b c = MkConst3 (Const a c)
-- Defined at /tmp/alpha-dbcdf.hs:10:5
instance Eq a => Eq (Const3 a b c)
-- Defined at /tmp/alpha-dbcdf.hs:10:100
instance Functor (Const3 a b)
-- Defined at /tmp/alpha-dbcdf.hs:10:59
instance Ord a => Ord (Const3 a b c)
-- Defined at /tmp/alpha-dbcdf.hs:10:103
instance Show a => Show (Const3 a b c)
-- Defined at /tmp/alpha-dbcdf.hs:10:107
instance Monoid a => Applicative (Const3 a b)
-- Defined at /tmp/alpha-dbcdf.hs:10:67
instance Foldable (Const3 a b)
-- Defined at /tmp/alpha-dbcdf.hs:10:79
instance Traversable (Const3 a b)
-- Defined at /tmp/alpha-dbcdf.hs:10:88
instance Monoid a => Monoid (Const3 a b c)
-- Defined at /tmp/alpha-dbcdf.hs:10:112
正如所料,您可以做到:
instance Monoid m => Category (Const3 m) where
id = Const3 mempty
Const3 x . Const3 y = Const3 (mappend x y)
链接地址: http://www.djcxy.com/p/43459.html
上一篇: Can I implement this newtype as a composition of other types?