F# 语法概览
F#和C#的语法差别
语法上,F#和C#有两个主要差别:
- 用缩进而非花括号分隔代码块
- 用空白而非逗号分隔参数
F#常见语法元素
以下是F#代码中常见的语法元素
注释
// 这是单行注释
(* 这是多行注释
第二行
最后一行 *)
let 绑定
let myInt =
let myFloat = 3.14
let myString = "hello"
上面的语句没有显式指定 myInt, myFloat, myString 的类型,类型由编译器推断。
列表
let twoToFive = [;;;] // 方括号表示列表,元素用分号分隔
let oneToFive = :: twoToFive // 符号 :: 将值添加到列表头部,得到新列表,结果为 [1;2;3;4;5]
let zeroToFive = [;] @ twoToFive // 符号 @ 连接两个列表,得到新列表,结果为 [0;1;2;3;4;5]
务必注意,列表元素使用分号分隔,而非逗号分隔。
函数
命名函数用 let 关键字定义,匿名函数用 fun 关键字定义。
let square x = x * x // 使用 let 定义命名函数,函数形参不用小括号围住
square // 运行函数,实参也没有小括号 let add x y = x + y // 不可使用 (x,y)
add // 运行函数 // 多行函数,用缩进,不用分号
let evens list =
let isEven x = x% = // 内部函数
List.filter isEven list // List.filter 是库函数 evens oneToFive // 运行函数 // 用小括号指明优先级
let sumOfSquaresTo100 =
List.sum (List.map square [..]) // 如果没有小括号,那么 List.map 会是 List.sum 的参数 // 管道 |>,将操作的输出传给下一个操作
let sumOfSquaresTo100piped =
[..] |> List.map square |> List.sum // 用 fun 关键字定义拉姆达(匿名函数)
let sumOfSquaresTo100withFun =
[..] |> List.map (fun x->x*x) |> List.sum
模式匹配
match..with 用于模式匹配
// 类似于 switch/case
let simplePatternMatch =
let x = "a"
match x with
| "a" -> printfn "x is a"
| "b" -> printfn "x is b"
| _ -> printfn "x is something else" // 下划线匹配任意值 // Some(..) 和 None 有点像可空类型(Nullable)
let validValue = Some()
let invalidValue = None // match..with 匹配 "Some" 和 "None",同时从 Some 中取出值
let optionPatternMatch input =
match input with
| Some i -> printfn "input is an int=%d" i
| None -> printfn "input is missing" optionPatternMatch validValue
optionPatternMatch invalidValue
复杂类型
复杂类型是指元组,记录和联合
// 元组,包含有序但未命名的值,值之间用逗号分隔
let twoTuple = ,2 // 二元组
let threeTuple = "a",,true // 三元组 // 记录,包含命名的字段,字段之间用分号分隔
type Person = {First:string; Last:string}
let person1 = {First="john"; Last="Doe"} // 联合,包含选项,选项之间用竖线分隔
type Temp =
| DegreesC of float
| DegreesF of float
let temp = DegreesF 98.6 // 类型可以递归的组合,例如,下面的 Employee 联合包含 Employee 类型的列表
type Employee =
| Worker of Person
| Manager of Employee list
let jdoe = {First="John";Last="Doe"}
let worker = Worker jdoe
格式化输出
printf 和 printfn 向控制台输出,类似于 C# Console 类的 Write 和 WriteLine 方法。sprintf 输出到字符串,类似于 String 类的 Format 方法。
printfn "Printing an int %i, a float %f, a bool %b" 2.0 true
printfn "A string %s, and something generic %A" "hello" [;;;] // 复杂类型具有内置的美观输出格式
printfn "twoTuple=%A,\nPerson=%A,\nTemp=%A,\nEmployee=%A" twoTuple person1 temp worker let str1 = sprintf "Printing an int %i, a float %f, a bool %b" 2.0 true
let str2 = sprintf "A string %s, and something generic %A" "hello" [;;;]
比较F#和C#:计算平方和
C#版,不使用 linq
public static class SumOfSquaresHelper
{
public static int Square(int i)
{
return i * i;
} public static int SumOfSquares(int n)
{
int sum = ;
for (int i = ; i <= n; i++)
{
sum += Square(i);
}
return sum;
}
}
F#版
let square x = x * x
let sumOfSquares n =
[..n] // 创建 1 到 n 的列表
|> List.map square // 对每个元素求平方,得到新列表
|> List.sum // 将平方列表求和
F# 语法噪音小,没有花括号,分号,并且在这里不需要显式指定类型。
C#版,使用 linq
public static class FunctionalSumOfSquaresHelper
{
public static int SumOfSquares(int n)
{
return Enumerable.Range(, n)
.Select(i => i * i)
.Sum();
}
}
使用 linq 改写的 C# 代码简洁很多,但不能消除语法噪音,参数和返回值的类型也是必须的,仍然不如 F# 版简洁。
例子:快速排序算法
快速排序算法的步骤是:
- 从列表中取出一个数作为基准
- 将小于基准的数放在左边,不小于基准的数放在右边
- 对基准两边的部分进行快速排序
下面是 F# 实现快速排序的例子
let rec quicksort list =
match list with
| [] -> []
| firstElem::otherElements ->
// 小于第一个元素的元素
let smallerElements =
otherElements
|> List.filter (fun e -> e < firstElem)
|> quicksort // 不小于第一个元素的元素
let largerElements =
otherElements
|> List.filter (fun e -> e >= firstElem)
|> quicksort // 连接成新列表
List.concat [smallerElements; [firstElem]; largerElements] printfn "%A" (quicksort [;;;;;;])
如果应用库函数和一些技巧,代码可压缩成:
let rec quicksort = function
| [] -> []
| first::rest ->
let smaller,larger = List.partition ((>=) first) rest
List.concat [quicksort smaller; [first]; quicksort2 larger]
参考网站:http://fsharpforfunandprofit.com/
F# 语法概览的更多相关文章
- 《Go并发编程实战》读书笔记-语法概览
<Go并发编程实战>读书笔记-语法概览 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 本篇博客我们会快速浏览一下Go的语法,内容涉及基本构成要素(比如标识符,关键字,子 ...
- ES6新语法概览
简介 ES6是JavaScript语言的新一代标准,加入了一些新的功能和语法,正式发布于2015年6月,亦称ES2015:该标准由ECMA(欧洲计算机制造联合会)的第39号技术专家委员会(TC39)制 ...
- 【Scala】新手入门,基础语法概览
目录 变量.常量和数据类型 var val 数据类型 条件表达式 块表达式 to循环 for循环 for推导式 scala中的方法和函数 方法的定义 函数的定义 函数和方法的区别 变量.常量和数据类型 ...
- ES6新语法
ES6新语法概览 简介 ES6是JavaScript语言的新一代标准,加入了一些新的功能和语法,正式发布于2015年6月,亦称ES2015:该标准由ECMA(欧洲计算机制造联合会)的第39号技术专家委 ...
- F#周报2019年第25期
新闻 Azure Notebook概览 SpecFlow 3就在这里了! 使用新的Try .NET模版创建交互式文档 逐渐演化的.NET Core框架 Dylan与Linebreakers Oslo ...
- [Oracle] 分析功能(1)- 语法
语法概览 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZGJhbm90ZQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQ ...
- 函数式编程之-初窥F#
大量讲解函数式编程语言的书籍最终都会用Fuctor,Monad,Monoids,范畴论等各种词汇吓退命令式语言玩家,所以我试图避开这些问题,揭开这些复杂词汇带来的具有实战意义的成果.另外我会尽量使用C ...
- F#周报2019年第44期
新闻 Elmish.WPF教程 介绍Orleans 3.0 GC配置历史 介绍ONNX运行时1.0 介绍微软Q&A(预览) 使用App中心持续布署与监控你的UWP,WPF与Windows Fo ...
- 20155331 2016-2017-2 《Java程序设计》第七周学习总结
20155331 2016-2017-2 <Java程序设计>第七周学习总结 教材学习内容总结 一.认识Lambda语法 1.Lambda语法概览 Arrays的sort()方法可以用来排 ...
随机推荐
- Handler消息传递机制——Handler、Loop、MessageQueue的工作原理
为了更好地理解Handler的工作原理,先介绍一下与Handler一起工作的几个组件. Message:Handler接收和处理的消息对象. Looper:每个线程只能拥有一个Looper.它的loo ...
- javaweb入门实例---servlet例子
1.编写servlet: TreeDataServlet.java package com.maggie.tree; import java.io.IOException; import javax. ...
- JSP EL表达式 param、paramValues的使用
JSP EL表达式 param.paramValues的使用: <%@ page language="java" import="java.util.*" ...
- 理解javascript中的Function.prototype.bind
在初学Javascript时,我们也许不需要担心函数绑定的问题,但是当我们需要在另一个函数中保持上下文对象this时,就会遇到相应的问题了,我见过很多人处理这种问题都是先将this赋值给一个变量(比如 ...
- arcpy.mapping实战-专题图制图自动化
arcpy.mapping实战-专题图制图自动化 by 李远祥 最初对arcpy.mapping感兴趣是因为一次大规模的专题地图调整的需要,由于某某单位利用ArcEngine编写的专题图出图系统,出现 ...
- IOS任务管理之NSThread使用
前言: 无论是Android还是IOS都会使用到多任务,多任务的最小单元那就是线程,今天学习总结一下IOS的NSThread使用. NSThread使用? 第一种方式实例化 //selector :线 ...
- java udp socket通信(仅发送)
实现功能:客户端发送一个字符串(可以为汉字),服务器端接收并显示 服务器端程序: package udpServer; import java.io.*; import java.net.*; /** ...
- static的加载先后顺序
1.静态变量的声明和赋值是分开的,静态变量会先被声明,赋值操做被放在了静态代码块中. 2.静态变量的赋值和静态代码块的执行顺序和代码的先后书写顺序相关. 3.静态代码块优先执行,其次构造方法,最后普通 ...
- 简述public private protected internal修饰符的访问权限
public 关键字是类型和类型成员的访问修饰符.公共访问是允许的最高访问级别.对访问公共成员没有限制. protected 关键字是一个成员访问修饰符.受保护成员在它的类中可访问并且可由派生类访问. ...
- Java Web(五) JSP详解(四大作用域九大内置对象等)
前面讲解了Servlet,了解了Servlet的继承结构,生命周期等,并且在其中的ServletConfig和ServletContext对象有了一些比较详细的了解,但是我们会发现在Servlet中编 ...