我正在尝试解决如何在Haskell中实现类型类的关联类型和常量的概念。
作为实践,我尝试为A*节点创建一个类型类。一个节点具有给定的traits:
- 可以与其他节点(即实现
Eq
、Data.Hashable
) - 相关函数
neighbours
提供相邻节点的列表(即,neighbours :: Node -> [Node]
) - 有一个启发式函数,它提供了节点之间的“距离”。
- 前面提到的距离是排序的 * 关联类型 *,必须是
Num
和Ord
。它不能简单地硬编码为使用float
或类似的东西,因为“距离”的概念可能有不同的精度要求,甚至可以在2D整数网格上使用类似曼哈顿距离的东西。 - 具有“零”和“无限”距离的关联值(尽管“无限”可以定义为99999、INT32 MAX等)。这取决于用户期望的类型)。
对于那些像我一样熟悉rust的人来说,与我试图定义的类型类相同的特征是:
trait NavNode : Eq + Hash + Sized {
type Distance: Ord + Add;
const INFINITY: Self::Distance;
const ZERO: Self::Distance;
fn heuristic(a: Self, b: Self) -> Self::Distance;
fn neighbors(self) -> Vec<Self>;
}
最接近于我所做的实现是这样的,但是我发现没有办法将相关的Distance
类型约束为Num
和Ord
,编译器不喜欢我对zero
和infinity
常量的定义或Distance a
的用法,它似乎坚持认为应该是某种Distance a0
。
{-# LANGUAGE TypeFamilies #-}
class (Eq a, Hashable a) => NavNode a where
type Distance a :: * -- How to tell it it's Num, Ord?
heuristic :: a -> a -> Distance a
neighbours :: a -> [a]
zero :: Distance a
infinity :: Distance a
1条答案
按热度按时间wb1gzix01#
这是一个编译代码的示例。为了简单起见,我删除了
Hashable
,但是您可以在真实的代码中重新添加它。请注意最后一行中的
@String
,这是强制性的,以便指定实际的示例。实际上,多个类型可以将Int
作为它们的关联距离类型,因此我们必须指定它来消除歧义。