Haskell 构造类似于 Rust trait 对象
Haskell construct analogous to Rust trait objects
Haskell支持类型classes,如等式:
class Eq a where
(==) :: a -> a -> Bool
Rust 对 type traits:
做同样的事情
pub trait Draw {
fn draw(&self);
}
现在,可以在 Haskell 中声明一个列表,其元素必须属于相等类型 class:Eq a => [a]
(我相信 a
被称为 约束类型 in Haskell)。但是,列表的元素仍然必须是同一类型!比如说,全部 Integer
或全部 Float
之类的。然而,在 Rust 中,可以有一个值列表(向量),其中每个值都实现了给定的特征,但它们不一定是相同的具体类型:Vec<Box<dyn Draw>>
。有没有办法在 Haskell 中做同样的事情?比如,我想要一个值列表,但我只关心每个值都属于某种类型 class 但不一定是相同的具体类型。
在Haskell中,您可以使用存在类型来表达“这种类型的一些未知类型class”。 (在旧版本的 GHC 中,您将需要一些标准扩展。)
class Draw a where
-- whatever the methods are
data SomeDraw where
SD :: Draw a => a -> SomeDraw
type MyList = [SomeDraw]
但是,请注意,这通常是矫枉过正,会导致 known anti-pattern。
例如,如果我们有一个 class 如下:
class Draw a where
draw :: a -> String
那么上面的类型 MyList
与 [String]
是同构的(或者至少在道德上是这样的)。与直接存储字符串相比,存储未知的“可绘制”对象没有任何优势,该对象的唯一方法是将其转换为字符串。另请注意 Haskell 是惰性的,因此您可以“存储尚未评估的字符串”,可以这么说。
无论如何,类型classes的存在量化也可以用通用的方式定义:
import Data.Kind
-- Ex has the same role of "dyn" in Rust here
data Ex (c :: Type -> Constraint) where
Ex :: c a => a -> Ex c
type MyList = [Ex Draw]
Haskell支持类型classes,如等式:
class Eq a where
(==) :: a -> a -> Bool
Rust 对 type traits:
做同样的事情pub trait Draw {
fn draw(&self);
}
现在,可以在 Haskell 中声明一个列表,其元素必须属于相等类型 class:Eq a => [a]
(我相信 a
被称为 约束类型 in Haskell)。但是,列表的元素仍然必须是同一类型!比如说,全部 Integer
或全部 Float
之类的。然而,在 Rust 中,可以有一个值列表(向量),其中每个值都实现了给定的特征,但它们不一定是相同的具体类型:Vec<Box<dyn Draw>>
。有没有办法在 Haskell 中做同样的事情?比如,我想要一个值列表,但我只关心每个值都属于某种类型 class 但不一定是相同的具体类型。
在Haskell中,您可以使用存在类型来表达“这种类型的一些未知类型class”。 (在旧版本的 GHC 中,您将需要一些标准扩展。)
class Draw a where
-- whatever the methods are
data SomeDraw where
SD :: Draw a => a -> SomeDraw
type MyList = [SomeDraw]
但是,请注意,这通常是矫枉过正,会导致 known anti-pattern。
例如,如果我们有一个 class 如下:
class Draw a where
draw :: a -> String
那么上面的类型 MyList
与 [String]
是同构的(或者至少在道德上是这样的)。与直接存储字符串相比,存储未知的“可绘制”对象没有任何优势,该对象的唯一方法是将其转换为字符串。另请注意 Haskell 是惰性的,因此您可以“存储尚未评估的字符串”,可以这么说。
无论如何,类型classes的存在量化也可以用通用的方式定义:
import Data.Kind
-- Ex has the same role of "dyn" in Rust here
data Ex (c :: Type -> Constraint) where
Ex :: c a => a -> Ex c
type MyList = [Ex Draw]