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-else is 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..with should 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-with expression.
  • The option type has functions such as IsSome, IsNone and Value, don’t use them! Instead use the Option module and the defaultArg function.
  • 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 box keyword.
  • To convert an object back to an primitive type, use the unbox keyword.
  • “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 a let! expression.
  • Rule 1: If you start with an unwrapped value, and then you wrap it (using return), then unwrap it (using bind), 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 (using return), 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 seq expression does allow yield but doesn’t allow return, while the async does allow return, but does not allow yield.
  • Rule: Combine(a,Zero) should be the same as Combine(Zero,a) which should the same as just a.
  • Rule: a + 0 is the same as 0 + a is the same as just a, where + means Combine and 0 means Zero.

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 的中间件)
  • 使用函数式编程,要多采用 “关系型数据库” 的设计模式,让数据相互独立,通过函数建立其关系。
posted @ 2020-12-09 21:14  cmdOptionKana  阅读(1000)  评论(0)    收藏  举报