给出像这样的签名或that one:
def foo[A, F[_]](implicit mon: Monoid[F[A]], pr: Pure[F]): F[A]
假设A是Char
,有没有办法获得String
而不是List[Char]
?
String
没有采用类型参数,因此我认为这是不可能的。什么是下一个最佳选择?现在,我在结果上使用mkString
,但这感觉不是最佳。
我认为String
是一个幺半群,零 ""
而追加 +
......
答案 0 :(得分:7)
可以说服String伪装成更高级的类型,因此允许foo
形式的函数适用。但是,Scala的类型推断目前还不能用于推断foo
的类型参数,所以你必须明确地提供它们,
// Assuming the the definitions of Pure and Monoid from Scalaz
type ConstString = {
type λ[X] = String
}
implicit def StringPure = new Pure[ConstString#λ] {
def pure[A](a: => A) = a.toString
}
val sm = implicitly[Monoid[String]]
val sp = implicitly[Pure[ConstString#λ]]
val f : String = foo[Char, ConstString#λ](sm, sp) // OK
请注意,Char
的{{1}}类型参数未使用且可以是任何内容,但必须是:在这种情况下,foo
是自然选择,但Char
}或Nothing
也可以。
请注意,此解决方案以Any
的特殊特征进行交易:所有类型的值都可转换为String
s,因此String
可以为所有类型pure[A](a : => A) : String
实现。为A
以外的类型复制此习惯用法很可能必须利用某种机制在String
的主体中实现特定于类型的案例(例如某种模式匹配)。
答案 1 :(得分:6)
我能想到的最佳解决方案是定义从List[Char]
到String
的隐式转换。
答案 2 :(得分:0)
您的分析,scala的类型系统将拒绝String,因为它不是“更高级的类型”* - > * 是正确的。也就是说,对于任何F,类型String都不能分配给F[_]
。你可以尝试(我没有检查过这个)隐式转换......
def foo[A, F[_], That](implicit mon: Monoid[F[A]], pr: Pure[F], FA_Is_That: F[A] <%< That)
...但是我怀疑这不会那么有用,因为你必须在必要时提供你自己的定制转换,但也因为性能很糟糕,假设这是代码的一个热门部分。
或,使用标准库,您可以使用CanBuildFrom
机制,但很明显很好这将与scalaz风格的类型组合
def foo[A, F[_], That](implicit mon: Monoid[F[A]], pr: Pure[F], b: CanBuildFrom[A, F[A], That]): That
当然,在方法的主体中,你需要使用构建器来构造返回值,而不是Monoid / Pure类型类,我怀疑它们有点多余。