2015-06-25 39 views
1

通过优良的“FP Scala中”工作由ChiusanoRúnar比亚尔纳松,曾试图通过#懒洋洋地实现流#takeWhile当一个奇怪的编译错误foldRight。鉴于在书中(也GitHub)下面的代码:调用非严格功能斯卡拉为明确的类型不能编译,推断类型的作品

trait Stream[+A] { 
    def foldRight[B](z: => B)(f: (A, => B) => B): B = 
    this match { 
     case Cons(h,t) => f(h(), t().foldRight(z)(f)) 
     case _ => z 
} 

case object Empty extends Stream[Nothing] 
case class Cons[+A](h:() => A, t:() => Stream[A]) extends Stream[A] 

object Stream { 
    def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = { 
    lazy val head = hd 
    lazy val tail = tl 
    Cons(() => head,() => tail) 
    def empty[A]: Stream[A] = Empty 
} 

我想:

def takeWhile_fold(p: A => Boolean): Stream[A] = 
    foldRight(empty[A])((it:A, acc:Stream[A]) => if (p(it)) cons(it, acc) else acc) 

但这给人的编译错误:

type mismatch; 
[error] found : (A, fpinscala.laziness.Stream[A]) => fpinscala.laziness.Stream[A] 
[error] required: (A, => fpinscala.laziness.Stream[A]) => fpinscala.laziness.Stream[A] 
[error]  foldRight(empty[A])((it:A, acc:Stream[A]) => if (p(it)) cons(it, acc) else ac 

但如果我删除类型在拉姆达,它的工作原理:

def takeWhile_fold(p: A => Boolean): Stream[A] = 
    foldRight(empty[A])((it, acc) => if (p(it)) cons(it, acc) else acc) 

Scala没有办法在调用代码中声明它应该是一个名称参数,是吗? (难道它甚至有意义的来电,这是决定接收器,对吧?)尝试:

def takeWhile_fold(p: A => Boolean): Stream[A] = 
    foldRight(empty[A])((it, acc: => Stream[A]) => if (p(it)) cons(it, acc) else acc) 

给出了另一个编译错误:

[error]  identifier expected but '=>' found. 
[error]  foldRight(empty[A])((it, acc: => Stream[A]) => if (p(it)) cons(it, acc) else acc) 
              ^
[error] ')' expected but '}' found. 
[error] } 
[error]^
[error] two errors found 

我已经解决了这个运动,但我问题是 - 为什么它不适用于显式类型?他们以某种方式强制执行严格规定,而接收方必须非严格吗?如果是这样,Scala中是否有语法,因此调用者可以发出信号:“是的,这是名称参数”?

回答

2

是,通过名字最终被签名的一部分。你可以想像通过翻译这个由名称参数由编译器实现:

def foo(n: => Int) = ... n ... 

这样:

def foo(n:() => Int) = ... n() ... 

这样做的副作用是,如果你引用的名称参数的多个次,他们将被多次评估。所以这个:

def bar(n: => Int) = n + n 
bar({ println("foo"); 5 }) 

将打印foo的返回10.这是相同的,因为这之前两次:

def bar(n:() => Int) = n() + n() 
bar {() => println("foo"); 5 } 

至于是否可以明确指出拉姆达需要通过名称参数...我我不确定。我试过这个:

def foo(f: (=> Int) => Int) = f({ println("foo"); 5 }) 
foo { (a) => a + a } 

哪些工作。我试过这些:

foo { (a : Int) => a + a } 
foo { (a : => Int) => a + a } 

哪个失败。

该规范似乎与该ParamType语法规则生成形式参数到函数的类型属性indicate,而的anonymous functions参数的类型属性使用纯Type规则。并且=>名称指示符在ParamType上。

相关问题