scala不是函数式语言,与Ocaml的对比

http://blog.enfranchisedmind.com/posts/scala-not-functional/
这篇文章,好像以前记录过,Manads are elepants的作者还写过 blog争论

看看里面一些比较:
1)柯里化和偏应用函数, scala里

[scala toolbar=”false” light=”true”]
def x(a:Int, b:Int) = a + b

def y = x(1) // 不能直接这样,而需要额外声明一下

def y = Function.curried(x _)(1) //2.8已经不鼓励这样用,而用: y = x(_:Int, 1)
[/scala]

2)代数数据类型(ADT)
Ocaml里:

[scala toolbar=”false” light=”true”]
type robert = Foo of int | Bar of string | Baz;;
[/scala]

Scala里:

[scala toolbar=”false” light=”true”]

sealed abstract class Robert;
sealed case class Foo(value:Int) extends Robert;
sealed case class Bar(value:String) extends Robert;
sealed case class Baz extends Robert;
[/scala]

james的回复:
http://james-iry.blogspot.com/2009/05/erlang-is-not-functional.html

scala中函数类型的多态

因为Function的泛型里定义了函数入参和出参分别是“逆变”“协变”的:
[scala]trait Function1[-T1, +R] {…}[/scala]

所以A=>B这样的函数类型,也可以有继承关系的。
我们做个测试,先简单些,只看出参类型的(协变容易理解些),A=>BA=>C两个函数类型;
如果C extends BA=>CA=>B的子类型
[scala]scala> class A; class B; class C extends B

//定义A=>C类型的函数
scala> val t2 = (p:A)=>new C

//可以把 A=>C类型的函数赋值给 A=>B类型的
scala> val t3:A=>B = t2

//或直接把t2造型为 A=>B
scala> t2.asInstanceOf[A=>B]
[/scala]
再看看入参类型,这个是逆变,继承关系正好相反。
假设: X=>R,Y=>R 如果 Y extends XX=>RY=>R 的子类型
[scala]scala> class R; class X; class Y extends X

//定义X=>R类型的函数
scala> val f1 = (x:X)=>new R

//把X=>R类型的函数赋值给 Y=>R 类型的
scala> val f2:Y=>R = f1

//或直接造型
scala> f1.asInstanceOf[Y=>R]
[/scala]
协变和逆变的场景与java泛型的”PECS原则”一致

注: PECS 是Joshua Bloch在《Effictive Java》里提出的一个原则。
当参数(容器)是一个生产者(producer)提供元素给你的代码来用(即容器只读),那么容器的泛型应该使用:

Collection< ? extends T >


当参数(容器)作为一个消费者(consumer)来消费你提供的数据(即容器可写),那么容器的泛型应该使用:

Collection< ? super T >