我可以将此newtype实现为其他类型的组合吗?

时间:2015-08-19 22:07:47

标签: haskell category-theory type-theory type-kinds polykinds

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

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

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

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

\a b c -> a
{p}告诉我的

等同于@pl

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

const

自动继承有用的实例,例如:

type Const3 = Compose Const Const

但GHC不同意:

instance Functor (Const m)
instance (Functor f, Functor g) => Functor (Compose f g)
-- a free Functor instance for Const3!

这似乎与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继承Const等实例的好处?

  

(作为旁注,引导我Compose的最初想法是写作:

Const3
     

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

2 个答案:

答案 0 :(得分:2)

令人困惑的事情 - 或者至少是混淆了我的事情 - *就像具体类型一样,不是类型变量。因此,如果没有PolyKindsCompose的类型更像是:

compose :: (A -> A) -> (A -> A) -> A -> A

至关重要的是,我们无法将A替换为A -> A因为它们属于不同类型,因此,按照相同的逻辑,我们无法替换* 1}}还有* -> *

即使使用PolyKinds,这些种类仍然不对。特别是,Compose期望(k -> *)作为其第一个参数,并且您正试图给它(k -> (k2 -> *))

您被迫返回*种类的原因是因为您正在使用newtypes,并且newtypes必须返回具体类型(即{{1}种类型})。我试图通过将*转换为最终具有我们想要的类型(使用Compose)的类型同义词来克服这个问题:

PolyKinds

然而,使用它仍然给我一个类似的错误,我不确定我们是否能让它正常工作。问题出现了,因为将type Compose f g a = (f (g a)) λ> :k Compose Compose :: (k1 -> k) -> (k2 -> k1) -> k2 -> k 应用于第一个Compose会给我们一个带有Const的类型,可能是因为类型别名的限制如下:

*

答案 1 :(得分:2)

从其他答案来看,似乎并不那么容易,但是如果你唯一想要的就是"免费"实例,一种快捷方法是使用newtype而不是常规Const并使用GeneralizedNewtypeDeriving扩展名:

{-# 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)