被视为Monoid的字符串

时间:2011-10-03 06:51:14

标签: scala scalaz

给出像这样的签名或that one

def foo[A, F[_]](implicit mon: Monoid[F[A]], pr: Pure[F]): F[A]

假设A是Char,有没有办法获得String而不是List[Char]

String没有采用类型参数,因此我认为这是不可能的。什么是下一个最佳选择?现在,我在结果上使用mkString,但这感觉不是最佳。

我认为String是一个幺半群, ""追加 + ......

3 个答案:

答案 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类型类,我怀疑它们有点多余。