5

给定一个像这样或那样的签名:

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

假设 A 是Char,有没有办法得到 aString而不是 a List[Char]

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

我认为String是一个带有 ""附加 +的幺半群......

4

3 回答 3

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类型参数foo是未使用的,可以是任何东西,但必须是某种东西:在这种情况下,要么Char是自然选择,Nothing要么Any也可以。

请注意,此解决方案以Strings 的特殊特性为基础:所有类型的值都可以转换为Strings ,因此对所有类型都pure[A](a : => A) : String可以实现A。将这个习语复制到其他类型String很可能必须利用一些机制来在主体中实现特定于类型的情况pure(例如,某种模式匹配)。

于 2011-10-03T09:50:39.340 回答
6

我能想到的最佳解决方案是定义从List[Char]to的隐式转换String

于 2011-10-03T08:09:14.273 回答
0

您的分析,scala 的类型系统将拒绝 String ,因为它不是“更高种类的类型” * -> * 是正确的。也就是说,F[_]任何 F 都不能分配 String 类型。您可以尝试(我没有检查过)隐式转换...

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 类型类,我怀疑它们会使它们有些多余。

于 2011-10-03T07:14:48.360 回答