![](/img/trans.png)
[英]What types of problems helps “higher-kinded polymorphism” solve better?
[英]What's the difference between parametric polymorphism and higher-kinded types?
我很確定他們不一樣。 但是,我對“ Rust不支持”更高種類的類型(HKT)而是提供參數多態性這一普遍觀念感到困惑。 我試圖繞開它並理解它們之間的區別,但是卻越來越糾結。
據我了解, 有魯斯特高kinded類型,至少是基本。 使用“ *”符號,HKT確實具有例如* -> *
。 例如, Maybe
是* -> *
的一種,可以在Haskell中這樣實現。
data Maybe a = Just a | Nothing
這里,
Maybe
是類型構造函數,需要將其應用於具體類型以成為類型“ *”的具體類型。 Just a
和Nothing
是數據構造函數。 在有關Haskell的教科書中,這通常被用作高種類型的示例。 但是,在Rust中,它可以簡單地實現為枚舉,它畢竟是sum類型 :
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階。 * -> * -> ... -> *
至少帶有一個箭頭的任何形式都是一階的 。 (* -> *) -> *
。 順序本質上是箭頭左側嵌套的深度,例如(* -> *) -> *
是二階的, ((* -> *) -> *) -> *
是三階的,依此類推(FWIW,相同的概念也適用於類型本身:二階函數是其類型具有例如(A -> B) -> C
形式的函數(A -> B) -> C
。
非地面類型的類型(順序> 0)也稱為類型構造函數 (某些文獻僅將地面類型的類型稱為“類型”)。 較高種類的類型(構造函數)是其種類較高的類型(順序> 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支持“代替”更高種類類型的參數多態是沒有道理的。 兩者都是相互補充的參數化的不同維度。 當您將兩者結合在一起時,您將擁有更高種類的多態性。
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]
。
這不僅僅是一個客廳的把戲。 它與參數多態性有很強的交互作用。 由於fmap
類型中的類型變量a
和b
不受類定義的約束,因此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
可以將特定形狀的函數用作任意數據類型中的設置器和獲取器。 這是導致lens
庫的兩個核心見解之一。 沒有這種抽象就不可能存在。
(就其價值而言,另一個關鍵的見解是將鏡片定義為類似的功能,從而使鏡片的構成成為簡單的功能構成。)
因此,不僅僅可以接受類型變量。 重要的部分是能夠使用與類型構造函數相對應的類型變量,而不是某些具體的(如果未知)類型。
參數多態性只是指函數不能在其定義中使用類型(或種類)的任何特定特征的性質。 這是一個完整的黑匣子。 標准示例是length :: [a] -> Int
,它僅適用於列表的結構 ,不適用於列表中存儲的特定值。
HKT的標准示例是Functor
類,其中fmap :: (a -> b) -> fa -> fb
。 與length
不同, a
具有*
, f
具有* -> *
。 fmap
還表現出參數多態性,因為fmap
不能在其定義中使用a
或b
的任何屬性。
fmap
表現出特殊的多態性,因為該定義可以針對為其定義的特定類型構造函數f
進行定制。 也就是說,有單獨的定義fmap
為f ~ []
f ~ Maybe
,等不同的是, f
是“申報”為類型類定義的一部分,而不是僅僅是定義的一部分fmap
。 (實際上,添加了類型類以支持某種程度的即席多態性。沒有類型類,則僅存在參數多態性。您可以編寫一個函數來支持一個具體類型或任何具體類型,但不支持兩者之間的某些較小的集合。)
我將繼續它:種類繁多的類型只是類型級別的高階函數。
但是花一點時間:
考慮一下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中,表達式必須具有帶有kind *
的類型,即“具體類型”。 任何其他類型,例如* -> *
。
例如,您不能創建Maybe
類型的表達式。 它必須是應用於諸如Maybe Int
, Maybe String
等之類的參數的類型。換句話說,就是完全應用的類型構造函數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.