使用`implicit def`

时间:2016-09-23 17:49:05

标签: scala typeclass

给出一个假的F类型类:

scala> trait F[A] {}
defined trait F

此定义使用context bound要求输入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")
        ^

然后我使用:

定义了F[String]
scala> implicit def fInstance(x: String) = new F[String] {}
fInstance: (x: String)F[String]

但是,我无法运行:

scala> f("foobar")
<console>:18: error: could not find implicit value for evidence parameter of type F[String]
       f("foobar")
        ^

因为我没有隐式F[String],而是String => F[String]

使用这样的implicit def来满足F[String]约束的正确方法是什么,即使用f类型成功调用String函数?

我通过以下方式开始工作:

scala> implicit val x: F[String] = implicitly[String => F[String]].apply("foobar")
x: F[String] = $anon$1@7b7fdc8

scala> f("foobar")
scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:230)
  at .f(<console>:12)
  ... 33 elided

但我不确定它是否是正确/干净的方式。

3 个答案:

答案 0 :(得分:1)

您定义了隐式转化。如果你想使用def来提供类型类实例,你只需编写相同的内容即可编写隐式val,但用def替换val。

arr1

通常你只需要使用def,如果你需要类型参数,就像这里一样。

import xlwings as xw
import win32api

def msg_box():
    wb = xw.Book.caller()
    win32api.MessageBox(wb.app.hwnd, "YourMessage")

或者

implicit def fInstance = new F[String] {}

答案 1 :(得分:0)

您的fInstance定义了隐式转化,即将String转换为F[String]的方法。为了生成类型类实例,可以使用接受隐式参数的方法:

implicit def fInstance(implicit x: String) = new F[String] {}

它通常在FP库中用于从另一个派生类型类派生:

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]可以对任何String进行操作,而不依赖于提供给函数的实际参数。当然,您始终可以明确提供实例:

f("foobar")(new F[String] { })

作为后续行动,类型类的重要部分是你可以临时定义它们,即根本无法访问FString的定义,你被迫范围隐含在Scala中并导入它们,所以它完全没问题。

答案 2 :(得分:0)

以下是您的定义的更简单版本(您可以从implicit删除fInstance):

implicit val singleFInstance: F[String] = fInstance("") // or fInstance("foobar"), etc.

这是否是正确的做法,在很大程度上取决于Ff应该是什么意思。

但一般来说:如果F实际上是一个类型类,fInstance(string)根据字符串(不仅仅是不同的实例,但行为不同)给出不同的结果,f& #39;签名是正确的,那么这是错误的,你应该接受调用f("foobar")没有意义。