我想出了如何處理受單個類約束的異構型別串列:
data Ex c = forall a. (c a) => Ex a
forEx :: [Ex c] -> (forall a. c a => a -> b) -> [b]
forEx [] _ = []
forEx (Ex a:r) f = f a : forEx r f
> forEx @Show [Ex 3, Ex (), Ex True] show
["3","()","True"]
看起來不錯,但在現實生活中,如果依賴于 1 個以上的約束,而不是顯示函式會更復雜。以此類推是行不通的:
嘗試 1:
forEx @(Show, Eq) [Ex 3, Ex (), Ex True] show
<interactive>:85:8: error:
? Expected kind ‘* -> Constraint’, but ‘(Show, Eq)’ has kind ‘*’
嘗試 2:
type ShowEq c = (Show c, Eq c)
> forEx @ShowEq [Ex 3, Ex (), Ex True] show
<interactive>:87:1: error:
? The type synonym ‘ShowEq’ should have 1 argument, but has been given none
嘗試 3 有效,但一次使用定義虛擬類和實體是笨拙的:
class (Show a, Eq a) => ShowEq1 a
instance (Show a, Eq a) => ShowEq1 a
forEx @ShowEq1 [Ex (3::Int), Ex (), Ex True] show
["3","()","True"]
uj5u.com熱心網友回復:
有了足夠的語言特性,就可以創建一個結合約束的約束:
{-# LANGUAGE RankNTypes, ConstraintKinds, GADTs, TypeApplications, MultiParamTypeClasses, FlexibleInstances, UndecidableSuperClasses #-}
data Ex c = forall a. (c a) => Ex a
forEx :: [Ex c] -> (forall a. c a => a -> b) -> [b]
forEx [] _ = []
forEx (Ex a:r) f = f a : forEx r f
class (c a, d a) => (Combined c d) a
instance (c a, d a) => (Combined c d) a
shown :: [String]
shown = forEx @(Combined Show Eq) [Ex 3, Ex (), Ex True] show
uj5u.com熱心網友回復:
我會這樣做:
{-# LANGUAGE DataKinds, GADTs, RankNTypes, StandaloneKindSignatures, TypeFamilies, TypeOperators #-}
import Data.Kind
type All :: [Type -> Constraint] -> Type -> Constraint
type family All cs t
where All '[] _ = ()
All (c ': cs) t = (c t, All cs t)
data Ex cs
where Ex :: All cs t => t -> Ex cs
forEx :: [Ex cs] -> (forall a. All cs a => a -> b) -> [b]
forEx [] _ = []
forEx (Ex x : xs) f = f x : forEx xs f
現在Ex引數化的不是單個類,而是類串列1。我們有All型別族,用于獲取類串列并將它們全部應用于同一型別,將它們組合成一個Constraint.
這意味著(與 class-to-combine-two-other-classes 方法不同)它現在支持您需要的任意數量的約束。
你可以這樣稱呼它2:
λ forEx @[Show, Eq] [Ex 3, Ex (), Ex True] show
["3","()","True"]
it :: [String]
1從技術上講,這不是類串列,而是需要一個更多型別引數來生成Constraint. 不過,單引數類將是您最常使用的類。
2當然,Eq它并不是一個非常有用的約束,因為如果沒有相同未知型別的另一個值,您實際上無法使用它,并且您已經丟棄了有關任何給定型別是否為相同型別的所有資訊。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/386998.html
標籤:哈斯克尔
下一篇:如何從型別級串列生成術語級串列?
