Scala博客最近对类型类模式似乎有很多热情,其中一个简单的类通过符合某些特征或模式的附加类添加了功能.作为一个极其简单的例子,简单的类:
case class Wotsit (value: Int)
Run Code Online (Sandbox Code Playgroud)
可以适应Foo的特点:
trait Foo[T] {
def write (t: T): Unit
}
Run Code Online (Sandbox Code Playgroud)
借助此类型类:
implicit object WotsitIsFoo extends Foo[Wotsit] {
def write (wotsit: Wotsit) = println(wotsit.value)
}
Run Code Online (Sandbox Code Playgroud)
类型类通常在编译时捕获,带有隐含,允许Wotsit及其类型类一起传递到更高阶函数:
def writeAll[T] (items: List[T])(implicit tc: Foo[T]) =
items.foreach(w => tc.write(w))
writeAll(wotsits)
Run Code Online (Sandbox Code Playgroud)
(在你纠正我之前,我说这是一个过于简单的例子)
但是,使用implicits假定在编译时已知项的精确类型.我发现在我的代码中经常不是这样的:我将列出某种类型的项目List [T],并且需要发现正确的类型类来处理它们.
Scala的建议方法似乎是在调用层次结构的所有点添加类型类参数.这可能会因为代码规模而变得烦人,并且这些依赖关系需要通过越来越长的链传递,通过它们越来越无关紧要的方法.这使得代码变得混乱并且难以维护,与Scala的相反.
通常,这是依赖注入将介入的地方,使用库在需要的时间点提供所需的对象.详细信息因为DI选择的库而异 - 我过去在Java中编写了自己的库 - 但通常注入点需要精确定义所需的对象.
麻烦的是,在类型类的情况下,在编译时不知道精确值.必须根据多态描述选择它.而且至关重要的是,类型信息已被编译器删除.清单是Scala的类型擦除解决方案,但我不清楚如何使用它们来解决这个问题.
Scala的哪些技术和依赖注入库会被人们建议作为解决这个问题的方法?我错过了一招吗?完美的DI库?或者这真的是它似乎的关键点吗?
我认为这有两个方面.在第一种情况下,需要类型类的点是通过直接函数调用从其操作数的确切类型已知的点到达的,因此足够的类型争论和语法糖可以允许类型类传递给指出它是必要的.
在第二种情况下,这两个点由屏障隔开 - 例如无法更改的API,或存储在数据库或对象存储中,或序列化并发送到另一台计算机 - 这意味着类型类可以' t与其操作数一起传递.在这种情况下,给定一个只在运行时知道其类型和值的对象,需要以某种方式发现类型类.
我认为函数式程序员习惯于假设第一种情况 - 使用足够先进的语言,操作数的类型总是可以知道的.David和mkniessl为此提供了很好的答案,我当然不想批评这些.但第二种情况确实存在,这就是我将依赖注入带入问题的原因.
今天我碰巧发现一个C#类可以以隐式和显式方式继承一个接口.这让我感到惊讶.如果C#以这种方式工作,那么当以不同方式引用时,一个实例的行为会有所不同.
interface IFoo
{
void DoSomething();
}
class Foo : IFoo
{
#region IFoo Members
public void DoSomething()
{
Console.WriteLine("do something implicitly");
}
#endregion
#region IFoo Members
void IFoo.DoSomething()
{
Console.WriteLine("do something explicitly");
}
#endregion
}
Foo f = new Foo();
f.DoSomething();
((IFoo)f).DoSomething();
Run Code Online (Sandbox Code Playgroud)
上面的代码运行和输出
do something implicitly
do something explicitly
Run Code Online (Sandbox Code Playgroud)
我相信这种C#设计会使行为不一致.也许强制一个C#类可以以隐式或expliict方式从一个接口继承,但不能同时从两个接口继承.
有没有理由为什么C#以这种方式设计?
为什么此代码无法编译,但在取消注释指示的行时成功编译?(我每晚都使用Scala 2.8).似乎显式调用string2Wrapper允许从该点隐式使用它.
class A {
import Implicits.string2Wrapper
def foo() {
//string2Wrapper("A") ==> "B" // <-- uncomment
}
def bar() {
"A" ==> "B"
"B" ==> "C"
"C" ==> "D"
}
object Implicits {
implicit def string2Wrapper(s: String) = new Wrapper(s)
class Wrapper(s: String) {
def ==>(s2: String) {}
}
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:感谢目前为止的答案,其中包括指向Martin Odersky评论的指针,
"没有显式结果类型的隐式转换只能在自己定义的文本中可见.这样,我们就避免了循环引用错误."
我仍然有兴趣找出1)"循环参考错误"的危险是什么?,2)为什么显式调用有什么不同?
是否有任何样式指南描述如何使用Scala implicits编写代码?
隐含非常强大,因此很容易被滥用.是否有一些通用的指导方针可以说明何时隐含是合适的,何时使用它们会掩盖代码?
如果我没有导入除Scala通常默认值之外的任何内容,那么范围内有多少含义(隐式转换)?
是否有完整的列表,最好按照他们可以采取行动的类型进行组织?
我以前见过这种代码很多次,最近一次是在scala-user邮件列表中:
context(GUI) { implicit ec =>
// some code
}
Run Code Online (Sandbox Code Playgroud)
context 定义为:
def context[T](ec: ExecutionContext)(block: ExecutionContext => T): Unit = {
ec execute {
block(ec)
}
}
Run Code Online (Sandbox Code Playgroud)
implicit当keeyword 置于lambda表达式参数前面时,它的目的是什么?
tl; dr:我如何做类似下面的编写代码:
def notFunctor[M[_] : Not[Functor]](m: M[_]) = s"$m is not a functor"
Run Code Online (Sandbox Code Playgroud)
' Not[Functor]',是这里的组成部分.
当'm'提供的不是Functor时,我希望它成功,否则编译器会失败.
解决:跳过问题的其余部分,然后直接回答下面的答案.
我粗略地说,我想要完成的是"负面证据".
伪代码看起来像这样:
// type class for obtaining serialization size in bytes.
trait SizeOf[A] { def sizeOf(a: A): Long }
// type class specialized for types whose size may vary between instances
trait VarSizeOf[A] extends SizeOf[A]
// type class specialized for types whose elements share the same size (e.g. Int)
trait FixedSizeOf[A] extends SizeOf[A] {
def fixedSize: Long
def sizeOf(a: A) …Run Code Online (Sandbox Code Playgroud) 我可以将一个带隐式参数的方法转换为函数吗?
trait Tx
def foo(bar: Any)(implicit tx: Tx) {}
foo _ // error: could not find implicit value for parameter tx: Tx
Run Code Online (Sandbox Code Playgroud)
我试图实现以下,最好是我可以以某种方式使它与普通调用一起工作withSelection(deleteObjects):
trait Test {
def atomic[A](fun: Tx => A): A
def selection: Iterable[Any]
def withSelection(fun: Iterable[Any] => Tx => Unit) {
val sel = selection
if (sel.nonEmpty) atomic { implicit tx =>
fun(sel)(tx)
}
}
object deleteAction {
def apply() {
withSelection(deleteObjects) // !
}
}
def deleteObjects(xs: Iterable[Any])(implicit tx: Tx): Unit
}
Run Code Online (Sandbox Code Playgroud)
我发现了这个问题,但就我所见,它并没有解决从方法到功能的问题.
是否有可能宣布类似的东西
type F = (Int, Boolean)(implicit String) => Unit
Run Code Online (Sandbox Code Playgroud)
在斯卡拉?
我已经阅读了关于scala.math.Integral的问题的答案但是我不明白当作为隐式参数传递时会发生什么.(我想我一般都理解隐式参数概念).Integral[T]
让我们考虑一下这个功能
import scala.math._
def foo[T](t: T)(implicit integral: Integral[T]) { println(integral) }
Run Code Online (Sandbox Code Playgroud)
现在我打电话给fooREPL:
scala> foo(0)
scala.math.Numeric$IntIsIntegral$@581ea2
scala> foo(0L)
scala.math.Numeric$LongIsIntegral$@17fe89Run Code Online (Sandbox Code Playgroud)
怎样的integral争论变得scala.math.Numeric$IntIsIntegral和scala.math.Numeric$LongIsIntegral?
implicit ×10
scala ×9
typeclass ×2
c# ×1
coding-style ×1
currying ×1
explicit ×1
inheritance ×1
scala-2.8 ×1
scalaz ×1