2

F# で文芸的なプログラミング (つまり cweb) を使用するには、関数を前方宣言できるようにする必要があります (つまり、関数を定義する前に使用します)。私は 2 つの方法を思いつきましたが、どちらも不快でした。もっと良いもの (プログラマにとって使いやすいもの) を考えられますか?

素晴らしいですが、多相関数では機能しません

// This can be ugly
let declare<'a>  = ref Unchecked.defaultof<'a>

// This has to be beautiful
let add = declare<float -> float>

let ``function I want to explain that depends on add`` nums = nums |> Seq.map !add

add := fun x -> x + 1.

醜いが、すべてで動作する

// This can be ugly
type Literate() =
static member Declare<'a, 'b>  (ref : obj ref) (x : 'a) : 'b =
                                    unbox <| (unbox<obj -> obj> !ref)
static member Define<'a, 'b> (func : 'a -> 'b) (ref : obj ref) (f : 'a -> 'b) =
                                    ref := box (unbox<'a> >> f >> box)

// This has to be beautiful
let rec id (x : 'a) : 'a = Literate.Declare idImpl x
and idImpl = ref null

let f () = id 100 + id 200

Literate.Define id idImpl (fun x -> x)
4

4 に答える 4

3

www.tryjoinads.orgを作成するとき、文芸的プログラミングと同じ考え方に従うツールを使用しました。ドキュメントは、実行可能な F# ソース コードに変換されるコード スニペットを含むマークダウンであり、スニペットは正しい順序である必要があります。(一部の文芸的なプログラミング ツールでは、ドキュメントはコメントで書かれていますが、考え方は同じです。)

さて、私は、コードをより複雑にして、読み書き可能なプログラミング スタイルで記述 (および文書化) できるようにすることは、多くの偶発的な複雑さをもたらし、読み書き可能なプログラミングの主な目的を無効にしていると考えています。

したがって、この問題を解決したい場合は、スクリプトを機能させるために必要なコード ブロックの順序を指定する注釈を付けて、読み書きのできるプログラミング ツールを拡張します (また、単純な前処理ツールを使用して、生成時にそれらを並べ替えることができます)。 F# 入力)。TryJoinads の [私のビルド スクリプトを見てください][1] を使用できます。これを拡張してこれを行うのはかなり簡単です。

TryJoinads に使用したツールには、出力からコード ブロックを非表示にするために使用できるいくつかのメタ タグが既に用意されているため、次のように記述できます。

## This is my page heading

    [hide]
    // This function will be hidden from the generated HTML
    // but it is visible to the F# compiler
    let add a b = a + b 

Here is the description for the other function:

   let functionThatUsesAdd x = add x x

And later on I can repeat `add` with more comments (and I can add an annotation
`module` to avoid conflicts with the previous declaration):

   [module=Demo]
   let add a b =
     // Add a and b
     a + b

関数を複製する必要があるため、これも完璧ではありませんが、少なくとも、生成されたブログ投稿または HTML ドキュメントが重要でないものによって不明瞭になることはありません。moduleしかしもちろん、ブロックの順序を指定するためにorのようなメタコマンドを追加するhideことはそれほど難しくなく、クリーンなソリューションになります。

要約すると、異なる F# コードや F# 言語ではなく、読み書きのできるプログラミング ツールが必要なだけだと思います。

于 2012-11-30T19:06:25.210 に答える
1

何かが足りないのかもしれませんが、なぜあなたはずっと行き、「それをきちんとやっていない」のですか?

最初に関数を使用する:

<<test.fs>>=
<<add>>
let inc = add 1

後で関数を宣言する:

<<add>>=
let add a b = a + b
于 2012-12-03T06:51:30.970 に答える
0

関数は F# のファースト クラス オブジェクトであるため、代わりにそれらを渡すことができます。これは、前方参照よりもはるかに優れた (そして依然として不変の) ソリューションを提供します。

let dependentFunction f nums = nums |> Seq.map f

let ``function I want to explain that depends on add`` nums =
    dependentFunction (fun x -> x + 1.) nums

また、ほとんどの場合、カリー化 (部分関数適用) を使用してコードをさらに単純化できるはずですが、seq<'T>通常は柔軟な型として使用されるため (C# 4.0 の共分散と同様)、F# の型推論は少し奇妙です。説明する:

// This doesn't work because of type inference on seq<'T>,
// but it should work with most other types.
let ``function I want to explain that depends on add`` =
    dependentFunction (fun x -> x + 1.)

ref最後に、F# でorを使用するための適切な経験則は、mutable(初期化するために) 値を 1 回だけ割り当てる場合は、そのコードを記述するためのよりクリーンで機能的な方法 (値を関数として渡す) がおそらくあるということです。パラメーター (上記のように) とlazy2 つのそのようなアプローチです)。明らかに、この規則には例外がありますが、その場合でも非常に控えめに使用する必要があります。

于 2012-11-30T15:30:35.193 に答える
0

私が言ったように、これは間違っています (そして、なぜこれを行っているのかについて、ブログ記事または FPish 投稿を公開する必要があります) が、ここに私の見解があります:

let ``function I want to explain that depends on add``
      (add : float -> float) = nums |> Seq.map add

let add = (+) 1.

let ``function I want to explain that depends on add`` = ``function I want to explain that depends on add`` add
于 2012-11-30T15:34:51.633 に答える