【发布时间】:2017-01-10 17:57:34
【问题描述】:
我想建模一个Mapper,它接收一个As (T[A]) 的容器,以便使用f: A => B 的函数我们得到另一个容器T[B]。经过数小时的实验(参见注释代码),我提出了以下解决方案:
sealed trait Mapper[ A, T[ A ], B ] {
//type Out <: T[B]
type Out[X] //= T[X]
def map( l: T[ A ], f: A => B ): Out[B]
}
object Mappers {
implicit def typedMapper[ A, T[ A ] <: Iterable[ A ], B ]: Mapper[ A, T, B ] =
new Mapper[ A, T, B ] {
override type Out[X] = Iterable[X]
//override type Out <: Iterable[ B ]
//def map( l: T[ A ], f: A => B ) : this.Out = {
def map( l: T[ A ], f: A => B ) : Out[B] = {
println( "map" )
l.map( f )
}
}
implicit def IntMapper = typedMapper[Int, List, Int]
}
//def testMapper[ A, T[ A ], B ]( l: T[ A ], f: A => B )( implicit mapper: Mapper[ A, T, B ] ): T[B] = {
def testMapper[ A, T[ A ], B ]( l: T[ A ], f: A => B )( implicit mapper: Mapper[ A, T, B ] ) : Mapper[A, T, B]#Out[B]= {
println( mapper )
mapper.map(l, f)
}
我现在可以按如下方式使用它:
import Mappers.IntMapper
val l9 = testMapper( List( 1, 2, 3 ), { x: Int => x + 1 } )
println(l9)
虽然它有效,但我仍然不知道如何将 Out 直接限制为 T[B]。如果我这样做,我似乎总是会遇到类型不匹配。谁能指出没有类型别名或直接使用T[B] 的更清洁/更简单的方法?
TIA
【问题讨论】:
-
您发布的代码无法编译,您能发布一个可以编译的版本吗?
-
您正在提供范畴论中所谓的“函子”的具体实现。有一个广泛使用的库,称为“scalaz”,以及“cat”。要获得好的总结,请查看blog.tmorris.net/posts/functors-and-things-using-scala/…
-
Mapper不是Functor:您可以限制可能的As 和Bs,而Functor必须适用于所有A和B。这使得它在某些情况下的用处大大降低,但我想它一定有一些用处。 -
我认为你得到类型不匹配的原因是当你
mapA => BoverT[A]whereT[A] <: Iterable[A]时,你没有得到T[?]回来;你会得到一个Iterable[B]。您失去了对原始Iterable的了解,因此默认的Out = T[A]不起作用。 -
@AlvaroCarrasco 对此表示歉意。代码已更正。 Jist 取消注释行
type Out[X] //= T[X]
标签: scala type-mismatch higher-kinded-types type-alias