我是否可以将这种新类型实现为其他类型的组合?

我写了一个与Const类似的新类型Const3 ,但包含三个给定类型参数中的第一个:

newtype Const3 a b c = Const3 { getConst3 :: a }

我可以为这种新类型定义很多有用的实例,但我必须自己完成。

但是,我在类型级别上应用的函数类似于函数

a b c -> a

@pl告诉我等价于const . const const . const

(.)const都有匹配的newtype包装: ComposeConst 。 所以我想我可以写:

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’

这似乎与ComposeConst的种类有关:

*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’

是什么赋予了? 有没有一些聪明的方法来做到这一点,所以我可以从ConstCompose获得继承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)

捕捉幺半群是单个对象类别的想法。 如果有一个解决方案仍然允许我以某种方式编写上述实例,那将会很好。)


令人困惑的事情 - 或者至少让我困惑的事情 - 就是*表现为具体类型,而不是类型变量。 因此,如果没有PolyKindsCompose的类型更像是:

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?

下一篇: creating MonadBaseControl instance for newtype