Haskell 中的部分应用类型

2023-12-15

基于this问题,在这段代码中

data Promise a b =  Pending (a -> b) | Resolved b | Broken

instance Functor (Promise x) where
    fmap f (Pending g) = Pending (f . g)

IF

g :: a -> b

then

Pending g :: Promise a b

also

f :: b -> c

因为存在f . g.

这意味着

Pending (f . g) :: Promise a c`.

包起来

fmap :: (b -> c) -> Promise a b -> Promise a c

Now fmap单独有这个签名(适应上面)

fmap :: Functor f => (b -> c) -> f b -> f c

仅当您假设f = Promise a。虽然最终产品看起来很合理,但您如何解释这种类型f或者等效地,部分应用的承诺的类型是什么Promise a?


在类型级别你有另一种编程语言,almost-哈斯克尔。特别是,您可以将类型视为具有构造函数并且能够部分应用。

为了更严格地看待这一点,我们引入了“类型的类型”,称为“种类”。例如,类型构造函数Int有善良

Int ::: *

我写的地方(:::)阅读“has kind”,尽管这不是有效的 Haskell 语法。现在我们还有“部分应用类型构造函数”,例如

Maybe ::: * -> *

它的函数类型就像您在值级别所期望的那样。


类型的概念有一个非常重要的概念——只有当值是类型时才可以实例化类型*。或者,例如,不存在类型的值Maybe

x :: Maybe
x = -- .... what!

事实上,甚至不可能表达除*我们期望该类型描述值的任何地方。

这导致 Haskell 中“类型级函数”的能力受到某种限制,因为我们不能普遍传递“未应用的类型构造函数”,因为它们并不总是有意义。相反,整个系统的设计使得只能构建合理的类型。

但允许表达这些“高级类型”的地方是类型类定义。


如果我们启用KindSignatures然后我们就可以直接写我们的类型的种类了。出现这种情况的一个地方是类定义中。这是Show

class Show (a :: *) where
  show :: a -> String
  ...

这是完全自然的,因为该类型的出现a在方法的签名中Show是有价值观的。

但当然,正如您在这里指出的,Functor是不同的。如果我们写出它的签名,我们就会明白为什么

class Functor (f :: * -> *) where
  fmap :: (a -> b) -> f a -> f b

这是一种非常新颖的多态性,更高级的多态性,所以你需要花一点时间来理解它。但值得注意的是f只出现在方法中Functor 正在应用到其他一些类型a and b。特别是,像这样的课程会被拒绝

class Nope (f :: * -> *) where
  nope :: f -> String

因为我们告诉系统f有善良(* -> *)但我们使用它就好像它可以实例化值,就好像它很友善一样*.


一般情况下我们不需要使用KindSignatures因为 Haskell 可以直接推断签名。例如,我们可以(事实上确实如此)写

class Functor f where
  fmap :: (a -> b) -> f a -> f b

哈斯克尔推断出这种f必须是(* -> *)因为它似乎适用于a and b。同样,如果我们编写不一致的内容,我们可能会失败“种类检查”,就像我们无法通过类型检查一样。例如

class NopeNope f where
  fmap :: f -> f a -> a

暗示f有善良* and (* -> *)这是不一致的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Haskell 中的部分应用类型 的相关文章

随机推荐