12

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

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

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

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

\a b c -> a

@pl告诉我相当于const . const.

两者(.)const都有匹配的新类型包装器: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’

这似乎与和的种类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等实例中获益?ConstCompose

(作为旁注,导致我的最初想法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)

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

4

2 回答 2

2

令人困惑的事情——或者至少让困惑的事情——是它*的行为就像一个具体的类型,而不是一个类型变量。所以没有PolyKinds,Compose的类型更像:

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

至关重要的是,我们不能用Awith代替,A -> A因为它们是不同的类型,所以,按照相同的逻辑,我们不能** -> *任何一种代替。

即使有PolyKinds,种类仍然不对。特别是,Composeexpects(k -> *)作为它的第一个参数并且你试图给它(k -> (k2 -> *))

您被迫返回*kind 的原因是因为您正在使用newtypes,而 newtypes 必须返回具体类型(即 kind *)。我试图通过Compose变成一个类型同义词来克服这个问题,它最终完全符合我们想要的类型(使用PolyKinds):

type Compose f g a = (f (g a))

λ> :k Compose
Compose :: (k1 -> k) -> (k2 -> k1) -> k2 -> k

但是,使用它仍然给我一个类似的错误,我不确定我们是否可以让它正常工作。出现问题是因为应用Compose到第一个Const给我们一个带有 a*的类型,可能是因为类型别名的限制如下:

λ> :k Compose Const
Compose Const :: (k -> *) -> k -> k1 -> *
于 2015-08-19T22:44:42.357 回答
2

从其他答案看来,这似乎并不容易,但是如果您只想拥有“免费”实例,那么一种快速的方法是使用带有扩展名newtype的常规方法:ConstGeneralizedNewtypeDeriving

{-# 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)
于 2015-08-21T17:26:20.520 回答