我很确定他们不一样。但是,我陷入了困境 “Rust不支持”高级类型(HKT)的常见概念,但是 而是提供参数多态。我试图了解这些并理解它们之间的区别,但却变得越来越纠结。
根据我的理解,Rust中的是更高级的类型,至少是基础知识。使用“*” - 符号,HKT确实有一种例如* -> *
。
例如,Maybe
属于* -> *
,可以在Haskell中实现。
data Maybe a = Just a | Nothing
下面,
Maybe
是一个类型构造函数,需要应用于具体类型
成为具体类型的“*”。Just a
和Nothing
是数据构造函数。在关于Haskell的教科书中,这通常被用作更高级别类型的示例。但是,在Rust中它可以简单地实现为枚举,毕竟它是和类型:
enum Maybe<T> {
Just(T),
Nothing,
}
区别在哪里?据我所知,这是一个 一个更好的类型的完美的例子。
Maybe
枚举不符合条件
HKT?在查看函数时,这种混乱仍然存在,我可以编写参数
需要Maybe
的函数,以及我对HKT作为函数的理解
参数。
fn do_something<T>(input: Maybe<T>) {
// implementation
}
再次,在Haskell中就像是
do_something :: Maybe a -> ()
do_something :: Maybe a -> ()
do_something _ = ()
导致第四个问题。
我经历了很多与该主题相关的问题(包括他们对博客的链接等),但我找不到我的主要问题(1和2)的答案。
感谢您提供的许多好的答案,这些答案都非常详细并且帮助很多。我决定接受Andreas Rossberg的回答,因为他的解释帮助我走上了正确的轨道。特别是关于术语的部分。
我真的被认为是善良* -> * ... -> *
的所有内容都是更高级的。强调* -> * -> *
和(* -> *) -> *
之间差异的解释对我来说至关重要。
答案 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
中的类型变量b
和fmap
不受类定义的约束,因此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
的最基本起点。)
函数focusFirst
和focusSecond
可以作为get
或set
的第一个参数传递,因为其类型中的类型变量f
可以与get
和set
中更具体的类型统一。能够在高级变量类型变量f
上进行抽象允许特定形状的函数可以用作任意数据类型中的setter和getter。这是导致lens
库的两个核心见解之一。没有这种抽象,它就不可能存在。
(对于它的价值,另一个关键的见解是将镜片定义为这样的功能,使镜片的组合成为简单的功能组合。)
所以不,除了能够接受一个类型变量之外还有更多。重要的部分是能够使用与类型构造函数对应的类型变量,而不是某些具体(如果未知)类型。
答案 2 :(得分:9)
参数多态只是指函数在其定义中不能使用类型(或种类)的任何特定特征的属性;它是一个完整的黑盒子。标准示例是length :: [a] -> Int
,它仅适用于列表的结构,而不是列表中存储的特定值。
HKT的标准示例是Functor
类,其中fmap :: (a -> b) -> f a -> f b
。与length
不同,a
有*
种,f
有* -> *
种。 fmap
也展示参数多态,因为fmap
无法在其定义中使用a
或b
的任何属性。
fmap
也表现出ad hoc多态性,因为定义可以定制到定义它的特定类型构造函数f
。也就是说,对fmap
,f ~ []
等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 Int
,Maybe String
等参数的类型。换句话说,完全应用类型构造函数。