是否有可能在Haskell中获得类型构造函数?

时间:2014-10-10 04:03:17

标签: haskell type-kinds

我正在使用Data.Typeable,特别是我希望能够生成特定类型的正确类型(比如*)。我遇到的问题是TypeRep允许我们执行以下操作(使用GHC 7.8中的版本):

let maybeType = typeRep (Proxy :: Proxy Maybe)
let maybeCon = fst (splitTyConApp maybeType)
let badType = mkTyConApp maybeCon [maybeType]

这里badType在某种意义上是Maybe Maybe类型的表示形式,它不是任何种类的有效类型:

> :k Maybe (Maybe)

<interactive>:1:8:
    Expecting one more argument to ‘Maybe’
    The first argument of ‘Maybe’ should have kind ‘*’,
      but ‘Maybe’ has kind ‘* -> *’
    In a type in a GHCi command: Maybe (Maybe)

我不是要在类型级别强制执行此操作,但我希望能够编写一个足够智能的程序,以避免在运行时构造此类型。我可以使用TypeRep的数据级术语执行此操作。理想情况下,我会有像

这样的东西
data KindRep = Star | KFun KindRep KindRep

并且功能kindOf包含kindOf Int = Star(可能真的是kindOf (Proxy :: Proxy Int) = Star)和kindOf Maybe = KFun Star Star,这样我就可以“检查”我的TypeRep值。

我认为我可以使用像Typeable这样的多金属类类手动来完成此操作,但我宁愿不必为所有内容编写自己的实例。我也不想回归到GHC 7.6并使用不同类型的Typeable类型的单独类型类的事实。我对从GHC获取此信息的方法持开放态度。

1 个答案:

答案 0 :(得分:12)

我们可以得到一种类型,但是我们需要在GHC中抛出一大堆语言扩展来实现这一点,包括(在这种情况下)超出可疑的UndecidableInstancesAllowAmbiguousTypes

{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE AllowAmbiguousTypes #-}

import Data.Proxy

使用KindRep

的定义
data KindRep = Star | KFun KindRep KindRep

我们定义Kindable可以确定其类型的事物的类

class Kindable x where
    kindOf :: p x -> KindRep

第一个例子很简单,*的所有内容都是Kindable

instance Kindable (a :: *) where
    kindOf _ = Star

获得更高级别的类型很难。我们将试图说,如果我们能够找到它的论点以及将它应用于论证的结果的类型,我们就可以找出它的类型。不幸的是,由于它没有争论,我们不知道它的论点是什么类型;这就是我们需要AllowAmbiguousTypes

的原因
instance (Kindable a, Kindable (f a)) => Kindable f where
    kindOf _ = KFun (kindOf (Proxy :: Proxy a)) (kindOf (Proxy :: Proxy (f a)))

结合起来,这些定义允许我们编写类似

的内容
 kindOf (Proxy :: Proxy Int)    = Star
 kindOf (Proxy :: Proxy Maybe)  = KFun Star Star
 kindOf (Proxy :: Proxy (,))    = KFun Star (KFun Star Star)
 kindOf (Proxy :: Proxy StateT) = KFun Star (KFun (KFun Star Star) (KFun Star Star))

请勿尝试确定像Proxy

这样的多金属类型
 kindOf (Proxy :: Proxy Proxy)

幸运的是,只在有限的时间内导致编译器错误。