参数多态与高等级类型有什么区别?

时间:2018-01-30 14:16:37

标签: haskell rust higher-kinded-types type-theory parametric-polymorphism

我很确定他们不一样。但是,我陷入了困境 “Rust不支持”高级类型(HKT)的常见概念,但是 而是提供参数多态。我试图了解这些并理解它们之间的区别,但却变得越来越纠结。

根据我的理解,Rust中的更高级的类型,至少是基础知识。使用“*” - 符号,HKT确实有一种例如* -> *。 例如,Maybe属于* -> *,可以在Haskell中实现。

data Maybe a = Just a | Nothing

下面,

  • Maybe是一个类型构造函数,需要应用于具体类型 成为具体类型的“*”。
  • Just aNothing是数据构造函数。

在关于Haskell的教科书中,这通常被用作更高级别类型的示例。但是,在Rust中它可以简单地实现为枚举,毕竟它是和类型

enum Maybe<T> {
    Just(T),
    Nothing,
}

区别在哪里?据我所知,这是一个 一个更好的类型的完美的例子。

  1. 如果在Haskell中这被用作HKT的教科书范例,为什么呢 说Rust没有HKT? Maybe枚举不符合条件 HKT?
  2. 是否应该说Rust不完全支持HKT?
  3. HKT和参数多态之间的根本区别是什么?
  4. 在查看函数时,这种混乱仍然存在,我可以编写参数 需要Maybe的函数,以及我对HKT作为函数的理解 参数。

    fn do_something<T>(input: Maybe<T>) {
        // implementation
    }
    

    再次,在Haskell中就像是

    do_something :: Maybe a -> ()
    do_something :: Maybe a -> ()
    do_something _ = ()
    

    导致第四个问题。

    1. 对高等级类型的支持到底在哪里?什么是 使Rust的类型系统无法表达HKT的最小例子?
    2. 相关问题:

      我经历了很多与该主题相关的问题(包括他们对博客的链接等),但我找不到我的主要问题(1和2)的答案。

      1. In Haskell, are "higher-kinded types" *really* types? Or do they merely denote collections of *concrete* types and nothing more?
      2. Generic struct over a generic type without type parameter
      3. Higher Kinded Types in Scala
      4. What types of problems helps "higher-kinded polymorphism" solve better?
      5. Abstract Data Types vs. Parametric Polymorphism in Haskell
      6. 更新

        感谢您提供的许多好的答案,这些答案都非常详细并且帮助很多。我决定接受Andreas Rossberg的回答,因为他的解释帮助我走上了正确的轨道。特别是关于术语的部分。

        我真的被认为是善良* -> * ... -> *的所有内容都是更高级的。强调* -> * -> *(* -> *) -> *之间差异的解释对我来说至关重要。

4 个答案:

答案 0 :(得分:31)

一些术语:

  • 种类*有时被称为 ground 。您可以将其视为第0个订单。
  • 任何具有至少一个箭头的* -> * -> ... -> *形式 first-order
  • 高阶类是指左侧有“嵌套箭头”的类型,例如(* -> *) -> *

顺序本质上是箭头左侧嵌套的深度,例如(* -> *) -> *是二阶,((* -> *) -> *) -> *是三阶等等。(FWIW ,同样的概念适用于类型本身:二阶函数是其类型具有例如(A -> B) -> C形式的函数。)

非地类的类型(顺序> 0)也称为类型构造函数(并且一些文献仅将地类的类型称为“类型”)。较高级的类型(构造函数)是其类型为高阶(order> 1)的类型。

因此,较高级的类型是采用非地类的论证。这将需要非地面类型的类型变量,这在许多语言中是不受支持的。 Haskell中的示例:

type Ground = Int
type FirstOrder a = Maybe a  -- a is ground
type SecondOrder c = c Int   -- c is a first-order constructor
type ThirdOrder c = c Maybe  -- c is second-order

后两者的关系更高。

同样,高度更高的多态性描述了(参数化)多态值的存在,这些值抽象了非基础类型。同样,很少有语言支持这一点。例如:

f : forall c. c Int -> c Int  -- c is a constructor

Rust支持参数​​多态“而不是更高级别的类型”的说法没有意义。两者都是参数化的不同维度,彼此互补。当你将两者结合起来时,你就拥有了更高的多态性。

答案 1 :(得分:16)

Rust不能做的一个简单例子就像Haskell的Functor类。

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

-- a couple examples:
instance Functor Maybe where
    -- fmap :: (a -> b) -> Maybe a -> Maybe b
    fmap _ Nothing  = Nothing
    fmap f (Just x) = Just (f x)

instance Functor [] where
    -- fmap :: (a -> b) -> [a] -> [b]
    fmap _ []     = []
    fmap f (x:xs) = f x : fmap f xs

请注意,实例是在类型构造函数Maybe[]上定义的,而不是完全应用的类型Maybe a[a]

这不仅仅是一个客厅伎俩。它与参数多态性有很强的相互作用。由于类型a中的类型变量bfmap不受类定义的约束,因此Functor的实例无法根据它们更改其行为。对于类型代码的推理,这是一个令人难以置信的强大属性,并且Haskell类型系统的优势来自于很多。

它还有另外一个属性 - 你可以在高级类型变量中编写抽象代码。以下是几个例子:

focusFirst :: Functor f => (a -> f b) -> (a, c) -> f (b, c)
focusFirst f (a, c) = fmap (\x -> (x, c)) (f a)

focusSecond :: Functor f => (a -> f b) -> (c, a) -> f (c, b)
focusSecond f (c, a) = fmap (\x -> (c, x)) (f a)

我承认,这些类型开始看起来像抽象的废话。但是当你有一些利用高级抽象的帮助者时,它们变得非常实用。

newtype Identity a = Identity { runIdentity :: a }

instance Functor Identity where
    -- fmap :: (a -> b) -> Identity a -> Identity b
    fmap f (Identity x) = Identity (f x)

newtype Const c b = Const { getConst :: c }

instance Functor (Const c) where
    -- fmap :: (a -> b) -> Const c a -> Const c b
    fmap _ (Const c) = Const c

set :: ((a -> Identity b) -> s -> Identity t) -> b -> s -> t
set f b s = runIdentity (f (\_ -> Identity b) s)

get :: ((a -> Const a b) -> s -> Const a t) -> s -> a
get f s = getConst (f (\x -> Const x) s)

(如果我在那里犯了任何错误,有人可以修复它们吗?我在没有编译器的情况下从内存中重新实现lens的最基本起点。)

函数focusFirstfocusSecond可以作为getset的第一个参数传递,因为其类型中的类型变量f可以与getset中更具体的类型统一。能够在高级变量类型变量f上进行抽象允许特定形状的函数可以用作任意数据类型中的setter和getter。这是导致lens库的两个核心见解之一。没有这种抽象,它就不可能存在。

(对于它的价值,另一个关键的见解是将镜片定义为这样的功能,使镜片的组合成为简单的功能组合。)

所以不,除了能够接受一个类型变量之外还有更多。重要的部分是能够使用与类型构造函数对应的类型变量,而不是某些具体(如果未知)类型。

答案 2 :(得分:9)

参数多态只是指函数在其定义中不能使用类型(或种类)的任何特定特征的属性;它是一个完整的黑盒子。标准示例是length :: [a] -> Int,它仅适用于列表的结构,而不是列表中存储的特定值。

HKT的标准示例是Functor类,其中fmap :: (a -> b) -> f a -> f b。与length不同,a*种,f* -> *种。 fmap 展示参数多态,因为fmap无法在其定义中使用ab的任何属性。

fmap也表现出ad hoc多态性,因为定义可以定制到定义它的特定类型构造函数f。也就是说,对fmapf ~ []f ~ Maybe有单独的定义。区别在于f是&#34;声明&#34;作为类型类定义的一部分,而不仅仅是fmap定义的一部分。 (实际上,添加了类型类以支持某种程度的特殊多态性。没有类型类,只存在 参数多态。您可以编写一个支持一个具体类型的函数或< em>任何具体类型,但中间不是一些较小的集合。)

答案 3 :(得分:8)

我要恢复它:一个更高级的类型只是一个类型级别的高阶函数。

但是花点时间:

考虑monad变形金刚:

newtype StateT s m a :: * -> (* -> *) -> * -> *

下面,

- s is the desired type of the state
- m is a functor, another monad that StateT will wrap
- a is the return type of an expression of type StateT s m

什么是更高级的类型?

m :: (* -> *)

因为它采用某种类型*并返回一种类型*

它类似于类型的函数,即类型的类型构造函数

* -> *

在像Java这样的语言中,你无法做到

class ClassExample<T, a> {
    T<a> function()
}

在Haskell中,T会有类*->*,但是Java类型(即类)不能有类型的类型参数,这是一种更高级的类型。

另外,如果您不知道,在基本的Haskell中,表达式必须具有类型*的类型,即“具体类型”。任何其他类型,如* -> *

例如,您无法创建Maybe类型的表达式。它必须是应用于Maybe IntMaybe String等参数的类型。换句话说,完全应用类型构造函数。