F# 的语法与基本特性
本文只是笔记/摘录,没有解释说明,因为原文有些句子太精彩了,忍不住要记下来,只是个人笔记,大家请看本博客的其他文章,这篇不用细看。
原文:
https://fsharpforfunandprofit.com/posts/expressions-vs-statements/
https://fsharpforfunandprofit.com/series/understanding-fsharp-types.html
https://fsharpforfunandprofit.com/posts/recipe-part3/
https://fsharpforfunandprofit.com/posts/computation-expressions-intro/
下面是摘录:
- In F# everything is an expression.
- Using expressions consistently leads to code that is both safer and more compact.
- In fact, it is not even helpful to think of “control flow” in a functional language; the concept doesn’t really exist.
- Better to just think of the program as a giant expression containing sub-expressions.
- If you need to work with a disposable “outside” the function that created it, probably the best way is to use a callback.
- One trick in F# is to appropriate the use keyword to do any kind of “stop” or “revert” functionality automatically.
- It is considered a good practice to always have an explicit “do”, as it acts as documentation that you do not want a result.
- The best way to avoid
if-then-elseis to use “match” instead. - The best way to avoid loops is to use the built in list and sequence functions instead.
- There is no equivalent of “break” and “continue” (this can generally done better using sequences anyway).
- In the functional world, returning error codes (or rather error types) is generally preferred to throwing exceptions.
- The
match..withshould be on a new line. - If you can’t have every case be explicit, you might try to document your boundary conditions as much as possible, and assert an runtime error for the wildcard case.
- You can match on subtypes, using the
:?operator - Partial active patterns have a return value that is an option type. (MSDN)
- To be as specific as possible when defining the domain, typically by creating lots of very specific types.
- Complicated logic is often a sign that you don’t quite understand the domain properly.
- A well designed object-oriented program will have a strong focus on behavior rather than data. A well designed functional program, on the other hand, will have a strong focus on data types rather than behavior.
- Tuples are perfect for small, temporary, lightweight structures.
- If you just need a single property, you can use dot notation rather than pattern matching. (Records)
- Note that in F#, unlike some other functional languages, two types with exactly the same structural definition are not the same type.
- The case constructors for union types are normal functions, so you can use them anywhere a function is expected.
- A convenient thing about single case union types is you can pattern match directly against a value without having to use a full
match-withexpression. - The option type has functions such as
IsSome,IsNoneandValue, don’t use them! Instead use theOptionmodule and thedefaultArgfunction. - It is good practice to immediately check for nulls and convert them into an option type!
- You can convert a primitive type to an object directly, by using the
boxkeyword. - To convert an object back to an primitive type, use the
unboxkeyword. - “It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures” – Alan Perlis
- In a functional design, it is very important to separate behavior from data.
- In a truly object-oriented design, you should have nothing but behavior – the data is private and can only be accessed via methods.
- If a type is shared among multiple modules, then put it in a special types-only module.
- If a type is private to a module (or two) then put it in the same module as its related functions.
- Dependencies can only happen when a specific type is referenced. If you use generic types, you cannot have a dependency!
- Parameterize, parameterize, parameterize.
- Because everything is an expression in F# we can’t do an early return, we have to cascade all the tests in a single expression.
computation expression
- a computation expression is: something that allows you to sneak your own code in to be called in the background, which in turn allows you to focus on the important code in the foreground.
- A continuation is simply a function that you pass into another function to tell it what to do next.
- The major uses of computation expressions: namely, to implicitly unwrap and rewrap values that are stored in some sort of wrapper type.
- In fact, every computation expression must have an associated wrapper type.
- Because a workflow returns a wrapper type, and because
let!consumes a wrapper type, you can put a “child” workflow on the right hand side of alet!expression. - Rule 1: If you start with an unwrapped value, and then you wrap it (using
return), then unwrap it (usingbind), you should always get back the original unwrapped value. - Rule 2: If you start with a wrapped value, and then you unwrap it (using
bind), then wrap it (usingreturn), you should always get back the original wrapped value. - Rule 3: If you create a child workflow, it must produce the same result as if you had “inlined” the logic in the main workflow.
- The operations without a “!” always have unwrapped types on the right hand side, while the ones with a “!” always have wrapped types.
- For example, the
seqexpression does allowyieldbut doesn’t allowreturn, while theasyncdoes allowreturn, but does not allowyield. - Rule:
Combine(a,Zero)should be the same asCombine(Zero,a)which should the same as justa. - Rule:
a + 0is the same as0 + ais the same as justa, where+means Combine and0meansZero.
The common naming conventions are as follows:
- “a”, “b”, “c” etc., are types
- “f”, “g”, “h” etc., are functions
- “x”, “y”, “z” etc., are arguments to the functions
- Lists are indicated by adding an “s” suffix, so that “xs” is a list of x’s, “fs” is a list of functions, and so on.
Formatted text using printf
https://fsharpforfunandprofit.com/posts/printf/
- %s for strings
- %b for bools
- %i for ints
- %f for floats
- %A for pretty-printing tuples, records and union types
- %O for other objects, using ToString()
我的想法
- 使用函数式编程,要多采用 middleware(中间件) 的设计模式。(是指类似于用 Go 写网站时的 http.HandlerFunc 的中间件)
- 使用函数式编程,要多采用 “关系型数据库” 的设计模式,让数据相互独立,通过函数建立其关系。

浙公网安备 33010602011771号