类型级别上的函数的模式匹配是可能的,但不是在值级别上,为什么会出现这种差异?

时间:2015-12-31 08:48:23

标签: haskell type-families higher-order-types

在SPJ的this论文中,在第3页和第4页,写着:

class Mutation m where
  type Ref m :: * -> *
  newRef :: a -> m (Ref m a)
  readRef :: Ref m a -> m a
  writeRef :: Ref m a -> a -> m ()

instance Mutation IO where
  type Ref IO = IORef
  newRef = newIORef
  readRef = readIORef
  writeRef = writeIORef

instance Mutation (ST s) where
  type Ref (ST s) = STRef s
  newRef = newSTRef
  readRef = readSTRef
  writeRef = writeSTRef

  

类声明现在引入了一个类型函数Ref(带有一个   指定类型)与通常的值函数(如newRef)一起使用   (每个都有指定的类型)。同样,每个实例声明   在实例类型中提供定义类型函数的子句   与每个价值功能的见证人一起。

     

我们说Ref是一种类型   家庭,或Mutation类的相关类型。它表现得像一个   类型级别的功能,所以我们也称Ref为类型函数。   应用类型函数使用与应用类型相同的语法   构造函数:参考上面的意思是将类型函数Ref应用于m,   然后将结果类型构造函数应用于。

所以,换句话说,

Ref :: (*->*)->*->*

即,Ref将类型级别函数作为参数,如MaybeIO[],并生成另一个类型级别函数,例如{{1}使用模式匹配,即IORef模式匹配定义。

那么,怎么可能在类型级别而不是在值级别上对函数进行模式匹配?

例如,

Ref

无法写入,因为函数上的相等性为undecidable

1)那么在类型级别上怎么可能没有问题呢?

2)是因为类型级别的函数排序非常有限吗?因此,类型级别上的任何类型的函数都不能是fun2int:: (Int->Int)->Int fun2int (+)=2 fun2int (*)=3 的参数,只有少数几个,即程序员声明的函数而不是(+)函数,这些函数比通过声明的函数更通用。程序员?这就是为什么在类型级别功能模式匹配导致没问题的原因?

3)这个问题的答案是否与GHC规范的this部分有关?

2 个答案:

答案 0 :(得分:7)

简而言之,类型级函数上没有模式匹配,但仅限于名称

在Haskell中,与许多其他语言一样,类型按名称分开,即使它们的表示相同。

data A x = A Int x
data B x = B Int x

上面,AB是两种不同的类型构造函数,即使它们描述了相同的类型级函数:粗略地在伪代码\x -> (Int, x)中。 从某种意义上说,这两个相同的类型级函数具有不同的名称/身份。

这与

不同
type C x = (Int, x)
type D x = (Int, x)

它们都描述了与上面相同的类型级函数,但是没有引入两个新的类型名称。以上只是同义词:它们表示一个函数,但没有自己独特的身份。

这就是为什么可以添加A xB x的类实例,而不是C xD x的实例:尝试执行后者会添加一个实例类型为(Int, x),而是将实例与类型名称(,)Int相关联。

在价值水平上,情况并没有那么大的不同。实际上,我们有值构造函数,它们是具有名称/标识的特殊函数,以及没有实际标识的常规函数​​。我们可以根据构造函数构建的模式进行模式匹配,但不能与其他任何内容进行匹配

case expOfTypeA   of A n t -> ... -- ok
case someFunction of succ -> ...  -- no

请注意,在类型级别,我们无法轻松进行模式匹配。 Haskell只允许使用类型类。这样做是为了保留一些理论属性(参数),并允许有效的实现(允许类型擦除 - 我们不必在运行时用其类型标记每个值)。这些功能的代价是限制类型级别模式匹配类型类 - 这确实给程序员带来了一些负担,但好处大于缺点。

答案 1 :(得分:7)

{-# LANGUAGE TypeFamilies, DataKinds, PolyKinds #-}
import GHC.TypeLits

让我们在Haskell中的类型和值级别之间绘制一些相似之处。

首先,我们在类型和价值级别都有无限制的功能。在类型级别,您可以使用类型系列表达几乎任何内容。 无法模式匹配任何类型或值级别的任意函数。例如。你不能说

type family F (a :: *) :: *
type family IsF  (f :: * -> *) :: Bool where
  IsF F = True
  IsF notF = False

-- Illegal type synonym family application in instance: F
-- In the equations for closed type family ‘IsF’
-- In the type family declaration for ‘IsF’

第二,我们已完全应用数据和类型构造函数,例如值级别上的Just 5 :: Maybe Integer或类型级别上的Just 5 :: Maybe Nat

可以对这些进行模式匹配:

isJust5 :: Maybe Integer -> Bool
isJust5 (Just 5) = True
isJust5 _ = False

type family IsJust5 (x :: Maybe Nat) :: Bool where
  IsJust5 (Just 5) = True
  IsJust5 x = False

注意任意函数和类型/数据构造函数之间的区别。构造函数的属性有时被称为 generativity 。对于两个不同的函数fg,某些f x = g x的{​​{1}}可能很有可能。另一方面,对于构造函数,x暗示f x = g x。这种差异使得第一种情况(任意函数上的模式匹配)不可判定,第二种情况(完全应用的构造函数上的模式匹配)可判定且易于处理。

到目前为止,我们已经看到了类型和价值水平的一致性。

最后,我们已部分应用(包括未应用)构造函数。在类型级别,这些包括f = gMaybeIO(未应用),以及[]Either String(部分应用)。在价值级别,我们未应用(,) IntJust,部分应用了Left(,) 5

生成条件并不关心申请是否已满;所以没有什么能阻止部分应用的构造函数的模式匹配。这就是你在类型层面看到的;我们也可以在价值水平上拥有它。

(:) True

不支持这一点的原因是效率。类型级别的计算 在编译时以解释模式执行;所以我们可以负担得起 携带大量关于类型和类型函数的元数据以进行模式匹配 它们。

编译价值级别的计算,并且需要尽可能快 可能。保持足够的元数据以部分支持模式匹配 应用的构造函数会使编译器复杂化并减慢程序的速度 运行;为这样一个异国情调的功能付出太多了。