将方法视为高阶函数
换句话说,方法并不是在运行时被“查找”,而是直接作为高阶函数传递。
引自 A Gentle Introduction to Haskell
从Rust学习Haskell,对我来说,类型类 在Haskell中有点像Rust trait的超强版本:两者都用来描述某些类型的集合,区别在于在Haskell中可以很容易地额外要求相关类型具备高阶种类,例如 * -> *,像 Functor。
但如果是那样,instance MyTypeClass 在Haskell应该大致对应于Rust中的 impl MyTrait。在Rust中,当我们调用trait方法时,所有东西都会被单态化到底(除非我们通过 dyn 让编译器不这么做),因此最终在编译期就已知的 j/jalr,等等,按ABI来看。
那么究竟有哪些东西被“作为高阶函数传递”呢?比如相关的类型类只是简单的 Eq 时?
解决方案
它在两种语言中确实非常相似,只是Rust默认对一切进行单态化,只有在通过 dyn 明确要求时才会生成字典包装;而Haskell默认传递字典,只有出于优化的目的才会用硬编码的实例来替换它们。
当你有一个像
foo :: Eq a => a -> a -> String
foo x y
| x==y = "equal"
| otherwise = "nonequal"
这样的函数时,这将变成
data EqDict a = EqDict
{ equal :: a -> a -> Bool }
foo :: EqDict a -> a -> a -> String
foo (EqDict eq) x y
| eq x y = "equal"
| otherwise = "nonequal"
……在运行时,类型并不存在,所以这基本上只是
type Pointer = Int
data EqDict = EqDict
{ equal :: Pointer -> Pointer -> Pointer }
foo :: EqDict -> Pointer -> Pointer -> Pointer
foo (EqDict eq) x y
| eq x y = "equal"
| otherwise = "nonequal"
只有在实际使用的点,也就是你对诸如 Char 参数调用 foo 时,编译器才会生成包含一个用于比较字符的函数的相应 EqDict 值。它会把这个作为隐式参数传递给 foo,而 foo 自身并不知道它正在处理字符。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。