F#vs Scala - 为什么我需要告诉F#什么类型的东西?

时间:2016-12-13 11:12:10

标签: scala f# functional-programming type-inference

我开始在F#(和Scala)中冒险。 FunProg人们喜欢谈论的主要好处之一是类型推断。在Scala中我可以这样写:

  val x = List(1,2,3)
  x map ((x) => x+1)

并且编译器知道x是一个列表,因此知道使用map函数的map变量。此外,我可以在任何具有map运算符的对象上使用第二个,不管它是什么(list,array,Seq,...)

另一方面,从我见过的关于F#的所有样本中,你必须做类似的事情:

let x = [1;2;3];;
x |> List.map(fun f -> f+1);;

所以我需要知道并定义x的类型是什么,并明确使用List.map。这对我来说没什么意义,并否定整个“不要担心类型”的论点。

我错过了关于F#的事情吗?有更好的方法吗?

2 个答案:

答案 0 :(得分:6)

这不是类型推理限制。问题是F#core lib不提供具有重载机制的泛型函数。实际上有一些,主要是针对通用数字和其他东西,但只是少数。

如果您想以该样式编写F#代码,可以查看F#+。使用该库,编写完全有效:

let x = [1;2;3];;
x |> map (fun f -> f+1);;

// val it : int list = [2; 3; 4]

它会为你推断出类型。

let y = Some 2
x |> map (fun f -> f+1);;

// val it : int option = Some 3

它也适用于任何具有Map静态方法的类型。

所以,正如你可以看到F#类型的推断,它也足够聪明。这只是因为函数是按模块组织的。

除了there is a proposal允许你写下这样的东西:

x |> _.map;;

x |> (.map);;

但这只适用于实例成员,因此对于List.map来说,它现在不会起作用。

答案 1 :(得分:1)

虽然它没有得到硬核FPers的太多喜爱,但实际上F#中有一个流畅的库,你可以去做它而不是做这样的事情:

    service rsync
    {
      disable = no
      socket_type = stream
      wait = no
      user = root
      server = /usr/bin/timeout
      server_args =  -k 60s 60s /usr/bin/rsync --daemon
      log_on_failure += USERID
      flags = IPv6
    }

当然Linq扩展方法也有效:

#if INTERACTIVE
#r @"..\packages\FSharp.Core.Fluent-4.0.1.0.0.5\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\FSharp.Core.Fluent-4.0.dll"
#endif

let x = [1;2;3]
x.map <| (+) 1 // ;-)
//val it : int list = [2; 3; 4]