在彙編程序中調用一個函數是在堆棧上推送參數(或根據調用約定寄存器)然後跳轉到函數地址的過程。
在更多高級語言中,例如Java,C#,C等等,這個過程或多或少都隱藏在我們的面前。但是,當我們調用不帶參數的函數時,我們會看到它的痕跡,即void
。在函數式編程語言(如F#,haskell等)中,函數的概念更接近於從單個輸入產生答案的數學函數。
地看到,在F#的所有函數接受單個輸入讓我們來看看下面的函數:
// val f: (int*int) -> int
let f (x,y) = x + y
f
接受一對整數,併產生一個整數。這兩個人從f
的角度來看,它解構了一個單一的價值來產生答案。
// val g: int -> int -> int
let g x y = x + y
顯然,這似乎是一個接受兩個整數從而產生一個整數的功能,但如果我們把它改寫略有我們看到事實並非如此:
// val h: int -> int -> int
let h x = fun y -> x + y
h
相當於g
但在這裏我們看到h
實際上只接收一個整數,該整數產生一個接受整數來產生整數的函數。
簽名中的->
是正確的聯想,我們添加了更多的偏見,我們更清楚地看到g
和h
實際上只是一個輸入。
// val g: int -> (int -> int)
let g x y = x + y
// val h: int -> (int -> int)
let h x = fun y -> x + y
let gx = g 1 2
let gy = (g 1) 2
let hx = h 1 2
let hy = (h 1) 2
在F#我看來,功能比功能的更高層次的抽象的說,C#/ Java作爲C#/ Java的功能在概念上更接近比F#的功能是彙編語言的功能。另外,如果每個函數都需要一個參數,那麼對於不接受參數的函數來說,這是沒有意義的。
但是這個功能呢?
// val i: unit -> int
let i() = 3
它不接受沒有參數產生3?不,它接受單位價值()
,這只是unit
類型中的價值。
在Haskell他們有一個名稱,接受void
,併產生一個答案功能:
absurd :: Void -> a
值或許可以看作是不帶參數的函數,但我不是一個範疇論專家。
再回到示例代碼:
type Function =
| UnitFunction of (unit -> unit)
| OperandFunction of (unit16 -> unit)
功能的方法將是這樣的:
type Abstraction =
| Concrete of obj
| Function of Abstraction -> Abstraction
Ie的Abstraction
是一個值或一個函數。
看看代碼,它似乎模仿了看起來接近彙編語言的東西,所以在這種情況下,可以將函數看作是推送參數並跳轉到地址。
type Function =
| VoidFunction of (unit -> unit)
| UnaryFunction of (unit16 -> unit)
| BinaryFunction of (unit16 -> unit16 -> unit)
希望這很有趣。
PS。
看起來好像unit
類型是一個小細節,但IMO使許多好東西。
- 無需聲明。
- 簡化通用編程(
void
案例通常需要特殊情況,考慮Task<'T>
和Task
)。
- 允許我們思考數學函數等功能,而不是跳轉到內存中的地址。
回覆:特殊的'void'情況下,C#中最震撼的一個是'Action'和'Func'類型之間的分割。 – scrwtp