【问题标题】:F# language - hints for newbie [closed]F# 语言 - 给新手的提示 [关闭]
【发布时间】:2008-08-30 19:42:24
【问题描述】:

看起来在 StackOveflow 中有一群 F# 爱好者。

我想更好地了解这种语言,所以,除了functional programming theory,您能否指出更好的起点来开始使用 F# 语言?我的意思是,教程、操作方法,但首先是工作示例,以便有机会开始做某事并享受语言。

非常感谢

安德烈亚

【问题讨论】:

    标签: f#


    【解决方案1】:

    不要让自己变得可怕,但我在我的博客 herehere 上写了几篇 F# 概述帖子。 Chris Smith(MS F# 团队的成员)有一篇名为“F# in 20 minutes”的文章 - part 1part 2

    请注意,您必须小心,因为 F# 的最新 CTP(版本 1.9.6.0)与以前的版本相比有一些严重的重大更改,因此如果不进行修改,某些示例/教程可能无法使用。

    这里是一些很酷的东西的简要介绍,也许我可以自己在这里给你一些提示,这些提示显然非常简短,可能不是很好,但希望能给你一些东西! -

    第一个注意事项 - 互联网上的大多数示例都假定“轻量级语法”已打开。要实现这一点,请使用以下代码行:-

    #light
    

    这使您不必插入某些为 OCaml 兼容性而存在的关键字,也不必用分号终止每一行。请注意,使用此语法意味着缩进定义范围。这将在后面的示例中变得清晰,所有这些都依赖于轻量级语法的开启。

    如果您使用交互模式,则必须用双分号终止所有语句,例如:-

      > #light;;
      > let f x y = x + y;;
    
      val f : int -> int -> int
    
      > f 1 2;;
      val it : int = 3
    

    请注意,交互模式在每一行之后都会返回一个“val”结果。这提供了有关我们正在创建的定义的重要信息,例如 'val f : int -> int -> int' 表示接受两个 int 的函数返回一个 int。

    请注意,只有在交互式中,我们才需要用分号结束行,而在实际定义 F# 代码时,我们没有这种情况:-)

    您使用“let”关键字定义函数。这可能是所有 F# 中最重要的关键字,您会经常使用它。例如:-

    let sumStuff x y = x + y
    let sumStuffTuple (x, y) = x + y
    

    我们可以这样调用这些函数:-

    sumStuff 1 2
    3
    sumStuffTuple (1, 2)
    3
    

    请注意,这里有两种不同的函数定义方式 - 您可以用空格分隔参数,也可以在“元组”中指定参数(即括号中的值用逗号分隔)。不同之处在于我们可以使用“部分函数应用”来获得使用第一种方法而不是第二种方法所需参数少于所需参数的函数。例如:-

    let sumStuff1 = sumStuff 1
    sumStuff 2
    3
    

    请注意,我们正在从表达式“sumStuff 1”中获取一个函数。当我们可以像传递数据一样容易地传递函数时,这被称为具有“一流函数”的语言,这是任何函数式语言(如 F#)的基本部分。

    模式匹配非常酷,它基本上就像类固醇上的 switch 语句(是的,我从另一个 F#-ist 中截取了这个短语 :-)。您可以执行以下操作:-

    let someThing x =
      match x with
        | 0 -> "zero"
        | 1 -> "one"
        | 2 -> "two"
        | x when x < 0 -> "negative = " + x.ToString()
        | _ when x%2 = 0 -> "greater than two but even"
        | _ -> "greater than two but odd"
    

    请注意,当我们想要匹配某些东西但我们返回的表达式不依赖于输入时,我们会使用“_”符号。

    我们可以根据需要使用 if、elif 和 else 语句来缩写模式匹配:-

    let negEvenOdd x = if x < 0 then "neg" elif x % 2 = 0 then "even" else "odd"
    

    F# 列表(在下面作为链表实现)可以这样操作:-

    let l1 = [1;2;3]
    l1.[0]
    1
    
    let l2 = [1 .. 10]
    List.length l2
    10
    
    let squares = [for i in 1..10 -> i * i]
    squares
    [1; 4; 9; 16; 25; 36; 49; 64; 81; 100]
    
    let square x = x * x;;
    let squares2 = List.map square [1..10]
    squares2
    [1; 4; 9; 16; 25; 36; 49; 64; 81; 100]
    
    let evenSquares = List.filter (fun x -> x % 2 = 0) squares
    evenSqares
    [4; 16; 36; 64; 100]
    

    注意 List.map 函数将 square 函数“映射”到从 1 到 10 的列表,即将函数应用于每个元素。 List.filter 通过仅返回列表中通过提供的谓词函数的值来“过滤”列表。还要注意 'fun x -> f' 语法 - 这是 F# lambda。

    请注意,自始至终我们都没有定义任何类型 - F# 编译器/解释器“推断”类型,即从使用中找出您想要的。例如:-

    let f x = "hi " + x
    

    这里编译器/解释器将确定 x 是一个字符串,因为您正在执行一个要求 x 是一个字符串的操作。它还确定返回类型也是字符串。

    当存在歧义时,编译器会做出假设,例如:-

    let f x y = x + y
    

    这里 x 和 y 可以是多种类型,但编译器默认为 int。如果要定义类型,可以使用类型注释:-

    let f (x:string) y = x + y
    

    还请注意,我们必须将 x:string 括在括号中,我们经常必须这样做以分隔函数定义的各个部分。

    F# 中两个真正有用且大量使用的运算符分别是管道转发和函数组合运算符 |> 和 >>。

    我们这样定义|>:-

    let (|>) x f = f x
    

    请注意,您可以在 F# 中定义运算符,这非常酷:-)。

    这可以让你以更清晰的方式写东西,例如:-

    [1..10] |> List.map (fun x -> x * x) |> List.filter (fun x -> x % 2 = 0)
    

    将允许您获得前 10 个偶数方格。这比:-

    List.filter (fun x -> x % 2 = 0) (List.map (fun x -> x * x) [1..10])
    

    好吧,至少我是这么认为的:-)

    >>运算符定义的函数组合定义如下:-

    let (>>) f g x = g(f(x))
    

    即你转发一个操作只有第一个函数的参数保持未指定。这很有用,因为您可以执行以下操作:-

    let mapFilter = List.map (fun x -> x * x) >> List.filter (fun x -> x % 2 = 0)
    

    这里 mapFilter 将接受一个列表作为输入并返回像以前一样过滤的列表。这是一个缩写版本:-

    let mapFilter = l |> List.map (fun x -> x * x) |> List.filter (fun x -> x % 2 = 0)
    

    如果我们想编写递归函数,我们必须通过在 let 后面放置 'rec' 来将函数定义为递归。下面的例子。

    一些很酷的东西:-

    阶乘

    let rec fact x = if x <= 1 then 1 else x * fact (x-1)
    

    第n个斐波那契数列

    let rec fib n = if n <= 1 then n else fib (n-1) + fib (n-2)
    

    FizzBu​​zz

    let (/%) x y = x % y = 0
    let fb = function
      | x when x /% 15 -> "FizzBuzz"
      | x when x /% 3  -> "Fizz"
      | x when x /% 5  -> "Buzz"
      | x              -> x.ToString()
    
    [1..100] |> List.map (fb >> printfn "%s")
    

    无论如何,这是一个非常简短的概述,希望对你有所帮助!

    【讨论】:

      【解决方案2】:

      毫无疑问,您应该购买 Don Syme 的优秀书籍“Expert F#”。这本书写得很好,适合初学者和专家。在其中,您会发现介绍性材料和更具挑战性的材料。它有近 600 页,物有所值。

      我发现它教会了我很多有用的技术来编写功能更强大的 C#,并提供了我开始编写 Windows 托管的 F# 应用程序所需的所有参考资料。

      这本书由 Apress 出版,并附有一个网站: http://www.expert-fsharp.com/default.aspx

      【讨论】:

        【解决方案3】:

        @kronoz - 非常感谢您的长篇回答,这是一个非常好的起点。我会听从你的建议,并寻找@vecstasy 提到的书。

        现在,让我去编码 :-)

        let thanksalot = "thanks a lot"
        printfn "%s" (thanksalot);;
        

        【讨论】:

        • 赞成纯粹是因为感谢代码。呵呵!
        【解决方案4】:

        我一直在阅读Real World Functional Programming

        F# 和 C# 中的示例作者:Tomas Petricek

        到目前为止,我发现它非常擅长通过在侧面展示 C# 中的实现来教授 F# 概念。非常适合 OO 程序员。

        【讨论】:

          【解决方案5】:

          我的 F# for Scientists 一书的第一章可免费获得here。我们有一系列免费的 F# 玩具程序here。我们 F#.NET 期刊的第一篇文章可免费获得 here

          【讨论】:

            【解决方案6】:

            查看F# Developer Center。还有hubFS,一个专门针对F#的论坛。

            【讨论】:

              【解决方案7】:

              如果您在 Visual Studio 中拥有当前的 CTP 版本,则可以创建一个 F# Tutorial 项目,该项目会为您提供一个 Tutorial.fs,其中包含其名称所暗示的内容。

              该教程还指向F# examples at Microsoft 的更大集合。

              另外,CodePlex 上还有一个 F# 示例项目。

              希望这会有所帮助,

              米歇尔

              【讨论】:

                猜你喜欢
                • 2010-09-07
                • 2016-08-04
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-07-26
                • 2013-05-22
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多