假设我有一个简单的类型类,其实例将为我提供某种类型的值:
trait GiveMeJustA[X] { def apply(): X }
Run Code Online (Sandbox Code Playgroud)
我有一些例子:
case class Foo(s: String)
case class Bar(i: Int)
implicit object GiveMeJustAFoo extends GiveMeJustA[Foo] {
def apply() = Foo("foo")
}
implicit object GiveMeJustABar extends GiveMeJustA[Bar] {
def apply() = Bar(13)
}
Run Code Online (Sandbox Code Playgroud)
现在我有一个类似(但不相关)的类型类,它做同样的事情,但在其类型参数中是协变的:
trait GiveMeA[+X] { def apply(): X }
Run Code Online (Sandbox Code Playgroud)
在它的伴随对象中,我们告诉编译器如何从非协变类型类的实例创建实例:
object GiveMeA {
implicit def fromGiveMeJustA[X](implicit giveMe: GiveMeJustA[X]): GiveMeA[X] =
new GiveMeA[X] { def apply() = giveMe() }
}
Run Code Online (Sandbox Code Playgroud)
现在我希望implicitly[GiveMeA[Foo]]编译得很好,因为只有一种方法可以获得GiveMeA[Foo]我们在这里得到的部分.但它没有(至少不在2.10.4或2.11.2):
scala> implicitly[GiveMeA[Foo]]
<console>:16: this.GiveMeA.fromGiveMeJustA is not a valid …Run Code Online (Sandbox Code Playgroud) 我正在使用猫Scala库,IntelliJ IDE似乎正在努力使用implicits:
这是一个简单的例子:
import cats.std.all._
import cats.Traverse.ops._
def useSequence[A](ls : List[Option[A]]) : Option[List[A]] = {
ls.sequence
}
Run Code Online (Sandbox Code Playgroud)
在IntelliJ中,此代码以红色突出显示.但是我可以使用Make Project或命令行构建得很好.
现在错误是:
类型Nothing [List [Nothing]]的表达式不符合预期类型选项[List [A]]
其他时候错误是这样的:
值序列不是List [Option [A]]的成员
这是IntelliJ中的错误还是我错过了一些配置?
我使用的是IntelliJ 15.0.2和Scala插件的2.0.4版.
我使用=:=示例类型lambda来制作简单的最小例子.
=:= 类型带两个参数,我想在类型级别讨好一个.
我采取天真的实现,type Curry[G] = {type l[L] = L =:= G}但在实际使用中它会导致错误:
type X = Int
type Y = Int
type CurryInt[T] = T =:= Int
type Curry[G] = {type l[L] = L =:= G}
type CurrStatic = {type l[L] = L =:= Int}
object CurryObj {type l[L] = L =:= Int}
trait Apply[P[_], T]
implicit def liftApply[P[_], T](implicit ev : P[T]) = new Apply[P,T] {}
implicitly[Apply[CurryInt, Y]] // ok
implicitly[Apply[Curry[X]#l, Y]] // fails
implicitly[Apply[Curry[X]#l, Y]](liftApply) …Run Code Online (Sandbox Code Playgroud) 我正在搞乱Scala 2.8以获得乐趣,并试图定义一个pimp,它为类型构造函数添加了一个"as"方法,允许从一个仿函数转换为另一个仿函数(请忽略我不一定在这里处理仿函数的事实) .例如,您可以像这样使用它:
val array:Array[T]
val list:List[T] = array.as[List]
Run Code Online (Sandbox Code Playgroud)
所以这就是我试图做的事情:
object Test {
abstract class NatTrans[F[_], G[_]] {
def convert[T](f:F[T]):G[T]
}
implicit def array2List:NatTrans[Array, List] = new NatTrans[Array, List] {
def convert[T](a:Array[T]) = a.toList
}
// this next part gets flagged with an error
implicit def naturalTransformations[T, F[_]](f:F[T]) = new {
def as[G[_]](implicit n:NatTrans[F, G]) = n convert f
}
}
Run Code Online (Sandbox Code Playgroud)
然而,定义的naturalTransformations标记为错误"不能存在抽象的参数化类型G [T]".要解决这个问题,我可以像这样重写naturalTransformations一个额外的类Transformable:
class Transformable[T, F[_]](f:F[T]) {
def as[G[_]](implicit n:NatTrans[F, …Run Code Online (Sandbox Code Playgroud) 假设我们有以下两个特征:
trait Foo[A] { def howMany(xs: List[A]) = xs.size }
trait Bar
Run Code Online (Sandbox Code Playgroud)
并且从第二个到第一个的隐式转换:
implicit def bar2foo[A](bar: Bar) = new Foo[A] {}
Run Code Online (Sandbox Code Playgroud)
我们创建一个Bar整数列表:
val bar = new Bar {}
val stuff = List(1, 2, 3)
Run Code Online (Sandbox Code Playgroud)
现在我希望以下工作:
bar howMany stuff
Run Code Online (Sandbox Code Playgroud)
但它没有:
scala> bar howMany stuff
<console>:13: error: type mismatch;
found : List[Int]
required: List[A]
bar howMany stuff
^
Run Code Online (Sandbox Code Playgroud)
所以我们去规范,其中有这样一段话(强调用粗体是我的):
视图适用于三种情况.
[这里不相关.]
在一个选择的EM与Ë类型的Ť,如果选择器米并不表示的成员Ť.在这种情况下,搜索视图v,其适用于e并且其结果包含名为m …
在Haskell有一个背景我目前正在尝试熟悉Scala.
我在尝试将一个小的,可扩展的表达式语言从Haskell转换为Scala时遇到了一些问题.编写可用新数据变量和操作扩展的数据类型的基本问题通常称为表达式问题.
我在Haskell中的原始解决方案使用带有约束的类型类和实例声明.我的表达式的基础定义如下:
module Expr where
class Expr e where
eval :: e -> Integer
data Lit = Lit Integer
instance Expr Lit where
eval (Lit l) = l
data Plus a b = (Expr a, Expr b) => Plus a b
instance (Expr a, Expr b) => Expr (Plus a b) where
eval (Plus x y) = (eval x) + (eval y)
Run Code Online (Sandbox Code Playgroud)
然后,我有一个数据扩展,增加了乘法:
module ExprWithMul where
import Expr
data Mul a b = (Expr a, Expr b) …Run Code Online (Sandbox Code Playgroud) 这个问题是关于Scala的隐式解析系统的局限性,我在使用Scalaz时遇到过几次,这对我来说没有多大意义.我已将问题提炼到下面的Scalaz-less版本,但如果需要,我很乐意提供有关动机的更多信息.
假设我有几个类型类见证了类型构造函数:
import scala.language.higherKinds
trait Foo[F[_]]
trait Bar[F[_], A]
Run Code Online (Sandbox Code Playgroud)
现在也假设如果我有一个Foo实例F,我知道我也有一个Foo实例Bar[F, _]:
implicit def barFoo[F[_]: Foo] = new Foo[({type L[X] = Bar[F, X]})#L] {}
Run Code Online (Sandbox Code Playgroud)
我也有实例List和右边Either:
implicit object listFoo extends Foo[List]
implicit def eitherFoo[A] = new Foo[({type L[X] = Either[A, X]})#L] {}
Run Code Online (Sandbox Code Playgroud)
现在很明显我应该能够编写以下内容:
type BarList[X] = Bar[List, X]
implicitly[Foo[BarList]]
Run Code Online (Sandbox Code Playgroud)
或者,等效地:
implicitly[Foo[({type L[X] = Bar[List, X]})#L]]
Run Code Online (Sandbox Code Playgroud)
事实上,两者都完全符合预期.
所以我尝试以下方法:
type StringOr[X] = Either[String, X]
type BarStringOr[X] = Bar[StringOr, X]
Run Code Online (Sandbox Code Playgroud)
然后:
scala> implicitly[Foo[BarStringOr]] …Run Code Online (Sandbox Code Playgroud) 考虑以下:
def f(implicit a: String, y: Int = 0) = a + ": " + y
implicit val s = "size"
println(f(y = 2))
Run Code Online (Sandbox Code Playgroud)
最后一个表达式导致以下错误:
not enough arguments for method f: (implicit a: String, implicit y:
Int)java.lang.String. Unspecified value parameter a.
Run Code Online (Sandbox Code Playgroud)
但是,如果为隐式参数a提供默认值,则没有问题:
def f(implicit a: String = "haha!", y: Int = 0) = a + ": " + y
implicit val s = "size"
println(f(y = 2))
Run Code Online (Sandbox Code Playgroud)
但最后一行打印
haha!: 2
Run Code Online (Sandbox Code Playgroud)
虽然我本来期待的
size: 2
Run Code Online (Sandbox Code Playgroud)
因此隐含值's'没有被提取.如果你没有为f提供任何参数而只是调用
println(f)
Run Code Online (Sandbox Code Playgroud)
那么隐含的价值就会被提起来
size: 0
Run Code Online (Sandbox Code Playgroud)
有人能否了解这里发生的事情?
我有这样一个特点:
trait CanFold[-T, R] {
def sum(acc: R, elem: T): R
def zero: R
}
Run Code Online (Sandbox Code Playgroud)
有一个像这样的功能:
def sum[A, B](list: Traversable[A])(implicit adder: CanFold[A, B]): B =
list.foldLeft(adder.zero)((acc,e) => adder.sum(acc, e))
Run Code Online (Sandbox Code Playgroud)
目的是做这样的事情:
implicit def CanFoldSeqs[A] = new CanFold[Traversable[A], Traversable[A]] {
def sum(x: Traversable[A], y: Traversable[A]) = x ++ y
def zero = Traversable()
}
sum(List(1, 2, 3) :: List(4, 5) :: Nil)
//=> Traversable[Int] = List(1, 2, 3, 4, 5)
Run Code Online (Sandbox Code Playgroud)
所以它是类型的类型,环境已经知道如何折叠,并且可以为Ints,Strings等定义.
我的问题是我想要具有更优先的更具体的含义,如下所示:
implicit def CanFoldSets[A] = new CanFold[Set[A], Set[A]] {
def sum(x: …Run Code Online (Sandbox Code Playgroud) 我使用Scala隐式类来扩展我经常使用的对象.作为一个例子,我有一个类似于Spark上定义的方法DataFrame:
implicit class DataFrameExtensions(df: DataFrame) {
def deduplicate: Boolean =
df.groupBy(df.columns.map(col): _*).count
}
Run Code Online (Sandbox Code Playgroud)
但是如果类已经定义了相同的方法,则不会调用隐式defs.如果我以后升级到定义DataFrame#deduplicate方法的新版Spark,会发生什么?客户端代码将静默切换到新的实现,这可能会导致细微的错误(或明显的错误,这些问题较少).
使用反射,如果在我的隐式定义它之前已经定义,我可以抛出运行时错误.从理论上讲,如果我的隐式方法与现有方法冲突,我可以检测它并重命名我的隐式版本.但是,一旦我升级Spark,运行应用程序并检测问题,使用IDE重命名旧方法为时已晚,因为现在任何引用都引用了本机Spark版本.我将不得不恢复我的Spark版本,通过IDE重命名该方法,然后再次升级.不是世界末日,而是一个伟大的工作流程.DataFramededuplicatedf.deduplicate
有没有更好的方法来处理这种情况?如何安全地使用"皮条客我的图书馆"模式?