gpt4 book ai didi

scala - 使用类型类时,如何以不同的方式处理对象?

转载 作者:行者123 更新时间:2023-12-02 20:29:13 25 4
gpt4 key购买 nike

假设我有一个类型类 Graph[G,V],它声明 G 类型的对象也是一个具有 V< 类型顶点的图.

现在我有一个隐式,可以让我将A类型对的集合视为具有A类型顶点的图(无法表达未连接的顶点.. .)。我可以通过导入以下对象的范围来使用隐式。

object TupleSetGraph{
implicit def ts2graph[A]: Graph[Set[(A,A)],A] = new Graph[Set[(A,A)],A] {
def nodes(g: Set[(A, A)]): Set[A] = g flatMap (t => Set(t._1,t._2))
def adjacent(g: Set[(A, A)], n1: A, n2: A): Boolean = g.contains((n1,n2)) || g.contains((n2,n1))
}
}

假设我还希望能够映射顶点的内容,从而能够执行以下操作:

(_: Set[(A,A)]).map((_: A => B)): Set[(B,B)]

但是Set上已经定义了一个map。如何处理相同的数据结构以不同的方式被视为同一事物(具有map功能的事物)的问题?

最佳答案

绘制一个可能的解决方案:

将 map 操作放在辅助特征中

GraphOps(可能是Graph本身,但 map 签名可能太复杂了)

case class GraphOps[G](data: G) { def map...}

轻松获取GraphOps:

object Graph {
def apply[G](data: G) = GraphOps(data)
}

这样,调用将是

Graph(set).map(f) 

apply 可以隐式设置,但我不确定我想这样做(如果我这样做,我不确定它能否正确找到 map )。

变体。将图表放入 GraphOps

我们也可以

case class GraphOps[G,V](data: G, graph: Graph[G,V])

object Graph {
def apply[G,V](data: G)(implicit graph: Graph[G,V]) = GraphOps(data, graph)
}

这样做的好处是顶点类型 V 在 GraphOps 中可用

定义 map 操作

您想要的签名很复杂,Set[(A,A)] 返回 Set[(B,B)],但其他图形实现返回完全不同的东西。这与集合库中的操作类似。

我们可以引入一个特征 CanMapGraph[From, Elem, To],类似于 CanBuildFrom

trait CanMapGrap[FromGraph, FromElem, ToGraph, ToElem] {
def map(data: FromGraph, f: FromElem => ToElem): ToGraph
}

(您可能会更改此设置,使其具有比映射更多的基本操作,以便它可以用于不同的操作,就像 CanBuildFrom 所做的那样)

那么 map 就是

case class GraphOps[G](data: G) {
def map[A,B](f: A, B)(implicit ev: CanMapFrom[G, A, B, G2]) : G2 =
ev.map(data, f)
}

您可以定义

implicit def mapPairSetToPairSet[A, B] = 
new CanMapGraph[Set[(A,A)], A, Set[(B,B)], B] {
def map(set: Set[(A,A)], f: A => B) = set.map{case (x, y) => (f(x), f(y))}
}

然后你就这样做

val theGraph = Set("A" -> "B", "BB" -> "A", "B" -> "C", "C" -> "A")
Graph(theGraph).map(s: String -> s(0).toLower)
res1: Set[(Char, Char)] = Set((a,b), (b,a), (b,c), (c,a))

这样做的一个问题是,第一个参数列表(即 f 的参数列表)中的顶点类型是未知的,因此我们必须明确使用 s: String。

使用替代的 GraphOps,我们可以提前获取顶点类型,A 不是 Map 的参数,而是 GraphOps 的参数,因此它从一开始就已知,不需要在 f 中明确显示。如果您这样做,您可能需要将图形传递给 CanMapGraph 中的 map 方法。

使用第一个解决方案,将图形提供给 CanMapGraph 仍然很容易。

implicit def anyGraphToSet[G,V,W](implicit graph: Graph[G,V]) 
= new CanMapFrom[G, V, Set[(W,W)], W] {
def map(data: G, f: V => W) =
(for {
from <- graph.nodes(data)
to <- graph.nodes(data))
if graph.adjacent(data, from, to) }
yield (from, to)).toSet
}

关于scala - 使用类型类时,如何以不同的方式处理对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7888169/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com