2016-09-15 13 views
3

Idrisで遊んだあと、の明示的なタイプを使用して、私のF#プログラムの宣言的自己文書化を強くすることになりました。F#に2種類の明示的な型宣言があるのはなぜですか?

の明示的な型を定義するは、F#が実際に関数に対して2つのスタイルの明示的な型を持っていることを再発見しました。 :を使用して標準関数関数スタイルがあり、->を使用するラムダ関数があります。例えば

// explicitly typed function using the classical let ':' style 
let OK1 (content : string) (context : Context) : Async<Context option> = 
    { context with Response = { Content = content; StatusCode = 200 } } 
    |> Some 
    |> async.Return 
// explicitly typed function using the '->' style 
let OK2 : string -> Context -> Async<Context option> = fun content context -> 
    { context with Response = { Content = content; StatusCode = 200 } } 
    |> Some 
    |> async.Return 

->スタイルのいいところは、私はそれを宣言することだと思うし、同じを使用しないよう

// type alias defining a webpart 
type WebPart = Context -> Async<Context option> 
// using the type alias in the declaration of an explicitly typed function 
let OK2 : string -> WebPart = fun content context -> 
    { context with Response = { Content = content; StatusCode = 200 } } 
    |> Some 
    |> async.Return 

として、私は型の別名を定義することができるということです:スタイルのエイリアス... ...?

なぜF#には、関数に明示的な型を宣言する2つのスタイルがあるのか​​不思議です。それは何らかの.Net制限ですか?それとも特別な目的を持っていますか? :ではなく、すべての明示的な型を->で定義してみませんか?

答えて

2

「明示的な型宣言」ではなく、型注釈をここで使用したいと思います。後者は、実際に存在するよりも多くのことが起こっていることを示唆しています - 型の注釈は、コンパイラ(そして時にはプログラマ)を案内するだけです。

ここには「2つのスタイル」はありません。ただ一つのスタイルがあります。注釈を付ける値があり、それに続いて:とタイプシグニチャーを付けます。 ->は、関数型名の一部です。上記のスニペットで

let OK2 : string -> Context -> Async<Context option> = fun content context -> 
    ... 

、あなたがOK2を結合letを持って、あなたはタイプstring -> Context -> Async<Context option>でそれに注釈を付け、あなたはそれのために価値を提供 - ちょうど機能であることを起こります。単純な値のバインディングを比較すると、これはまったく同じ構文です。

let simpleValue : int = 42 

これは特に便利な機能の考え方ではありません。値ではなく、いくつかの引数をとり、結果を返すエンティティとして考えることがより便利です。そして、これが略語宣言が取り上げるものです。あなたがここにWebPartエイリアスを使用することはできません右のようにしている

let OK2 (content: string): Context -> Async<Context option> = fun context -> 
    ... 

:あなたはaludeように見えるようしかし、それはそうでない場合、これは可能ではない、全く異なる、別のスタイルではありません。あなたがもはやエイリアスタイプの値を持っていないと考えると、驚くべきことではありません。

私は、そのような方法でエイリアスを使用する価値があることに同意します。一見すると機能がより均一に見えるようになり、APIの可読性と発見性が向上しますが、同時に、個々の機能の実装をより複雑にすることで価格を払います。常にトレードオフが伴う。

1

2つのオプションは完全に同等です。つまり、まったく同じことを意味し、まったく同じ方法でコンパイルされます。最初のオプションは、ショートカットの一種として存在します。次の2つを比較してください。

let f = fun a b -> a + b 
let f a b = a + b 

もう1つは短く読みやすいです。

+1

私は提示されたケースに同意します。この例は明示的な型とは関係がないようですが。私は主にラムダスタイルと 'ノーマル'スタイルの間で明示的な型定義が異なることに興味があります。通常のスタイルでは、明示的な型宣言で 'type WebPart = Context - > Async 'のような型エイリアスを使用する能力が失われているようです。 – Michelrandahl

+1

http://stackoverflow.com/questions/39394254/value-restriction-the-type-bar-has-been-inferred-to-have-generic-typeと比較してください。その点で、「2つのオプションは完全に同等です」というステートメントは成立しない可能性があります。しかし、確かに。 – BitTickler

+0

はい、そのコンテキストでその概念は成り立ちます。 'foo'は普通の関数です。その定義は' let foo a b = ... 'と同じですが、' bar'は異なります。 –

関連する問題