Scala 使用`隐式定义`
给定一个组合的Scala 使用`隐式定义`,scala,typeclass,Scala,Typeclass,给定一个组合的F类型类别: scala> trait F[A] {} defined trait F 此定义使用上下文绑定要求输入a具有类型类实例F: scala> def f[A : F](x: A) = ??? f: [A](x: A)(implicit evidence$1: F[A])Nothing 我定义了一个Person并键入类实例: scala> case class Person(name: String) defined class Person sca
F
类型类别:
scala> trait F[A] {}
defined trait F
此定义使用上下文绑定
要求输入a
具有类型类实例F
:
scala> def f[A : F](x: A) = ???
f: [A](x: A)(implicit evidence$1: F[A])Nothing
我定义了一个Person
并键入类实例:
scala> case class Person(name: String)
defined class Person
scala> implicit val person: F[Person] = new F[Person] {}
person: F[Person] = $anon$1@262b2c86
汇编如下:
scala> f(Person("foo"))
scala.NotImplementedError: an implementation is missing
但是,没有String
实现,所以它失败了
scala> f("foobar")
<console>:17: error: could not find implicit value for evidence parameter of type F[String]
f("foobar")
^
但是,我不能跑:
scala> f("foobar")
<console>:18: error: could not find implicit value for evidence parameter of type F[String]
f("foobar")
^
但是我不确定这样做是否正确/干净。您的
fInstance
定义了一种隐式转换,即将字符串
转换为F[String]
。要生成typeclass实例,可以使用接受隐式参数的方法:
implicit def fInstance(implicit x: String) = new F[String] {}
它通常在FP库中用于从一个typeclass派生另一个typeclass:
implicit def optionMonoid[A](implicit S: Semigroup[A]): Monoid[Option[A]] = ???
// or, which is the same
// implicit def optionMonoid[A: Semigroup]: Monoid[Option[A]] = ???
其思想是,F[String]
通常可以对任何字符串进行操作,而不依赖于函数中提供的实际参数。当然,您始终可以显式地提供实例:
f("foobar")(new F[String] { })
作为后续工作,TypeClass的重要部分是您可以临时定义它们,即根本无法访问
F
和String
的定义,并且您必须在Scala中定义隐式并导入它们,所以这完全没问题。您定义了隐式转换。如果您想使用def来提供typeclass实例,只需编写与编写隐式val相同的内容,但用def替换val即可
implicit def fInstance = new F[String] {}
通常,只有在需要类型参数时才使用def,如下所示
implicit def fInstance[A] = new F[List[A]] {}
或
以下是您定义的一个简单版本(您可以从
fInstance
中删除隐式):
这是否正确,很大程度上取决于F
和F
的含义
但一般来说:如果F
确实是一个类型类,fInstance(string)
根据字符串给出不同的结果(不仅是不同的实例,还有不同的行为),并且F
的签名是正确的,那么这是错误的,您应该接受调用F(“foobar”)
没有意义。如果不知道type类要捕获哪些信息和操作,那么很难回答这个问题,但是考虑到这个特殊的F
,您可以用与Person
实例完全相同的方式定义字符串
实例。在这种情况下,我只能构造F[String]
如果提供了字符串,即F[String]
实例依赖于字符串
参数。接下来,在伴生类之外使用隐式
是否不好,即孤立的隐式
实例?fInstance
不是typeclass实例,而是隐式转换,您必须在Scala中定义隐式并导入它们,因此它是这完全没问题。
你能说一下这句话是如何应用于(或不应用于)孤儿隐式的吗?@KevinMeredith你不能简单地在源代码中写def
或val
(如果是应用程序代码而不是Scala脚本的话)-它必须属于一个对象或类。因此,您必须使用对象隐式{implicit def fString:F[String]=???}
,但您不能在其他代码中使用它,除非在使用之前在其中导入隐式.fString
。
implicit def fInstance = new F[String] {}
implicit def fInstance[A] = new F[List[A]] {}
implicit def fInstance[A](implicit ev: F[A]) = new F[List[A]] {}
implicit val singleFInstance: F[String] = fInstance("") // or fInstance("foobar"), etc.