【问题标题】:switch function and object with scalaz' |>使用 scalaz' 切换函数和对象 |>
【发布时间】:2011-06-09 15:27:00
【问题描述】:

当我想切换函数和对象时,我可以使用scalaz |> 运算符,这样可以获得更多的可读性。让我给你介绍一个模型函数:

def length2(x:String) = x.length * 2
现在,我可以两种写法:
"aoeu" |> length2
length2("aoeu")
但如果我将这个函数定义得更通用,它就会停止工作。
def length2(x:SeqLike[_,_]) = x.length * 2
length2("aoeu") // ok
"aoeu" |> length2 // doesn't work
为什么编译器不理解这个?从String 到特征SeqLike 中的某些类混合肯定存在隐式转换。

【问题讨论】:

  • 棘手。一开始我以为是因为一次只能隐含一个,但现在看来这可能也是隐藏在某个地方的方差问题……
  • @Debilski,我不确定 |> 在 scalaz 中的定义位置,但是当我尝试定义自己的时,我认为“只有一个隐式规则”阻止了它的应用: "aoeu" 需要使用|> 方法隐式转换为类,然后再转换为SeqLike
  • 显示错误信息。不是每个人都有现成的 Scalaz,但错误消息通常会说明问题所在。

标签: scala scalaz


【解决方案1】:

除非必要,否则不要使用存在类型。他们破坏了东西,这里不需要。

另一方面,看到另一个答案中的错误使事情更加清楚。当您使用|> 时,会要求您进行两次隐式转换。如果你这样声明它是否有效:

def length2[CC <% SeqLike[_, _]](x: CC) = x.length * 2

【讨论】:

  • 返回:could not find implicit value for evidence parameter of type (CC) =&gt; scala.collection.SeqLike[_, _]
【解决方案2】:
scala> "aoeu" |> length2
<console>:14: error: type mismatch;
 found   : (scala.collection.SeqLike[_, _]) => Int
 required: (java.lang.String) => ?
       "aoeu" |> length2

错误信息很清楚。

虽然有从StringSeqLike[_,_] 的隐式转换,但没有从(SeqLike[_, _]) =&gt; IntString =&gt; ? 的转换。

这可以使用以下隐式转换来解决:

implicit def liftFun[X, T <% X, U](f: (X) => U): (T) => U = {
  def g(t:T) = f(t)
  g _
}

编辑 2:这里是一个非 scalaz 运算符。

class Pipe[T](t:T) {
  def |%>[X, U](f: (X) => U)(implicit ev: T <%< X) = f(t)
}
implicit def toPipe[T](t:T) = new Pipe(t:T)

那么你可以这样使用它:

def l1(a:String) = a.length
def l2(a:Seq[_]) = a.length * 2

"abc" |%> l1
"abc" |%> l2

只要有证据表明从TX 的隐式转换,它就允许|%&gt; 采用不能直接在T 上但在X 上工作的函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-09
    • 2012-12-04
    • 2016-08-20
    • 2015-05-21
    • 2013-06-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多