4

私はf#を学んでいるだけなので、おそらく私は非常にばかげたことをしています。関連するドキュメントを自由に教えてください。検索しましたが見つかりませんでした。Windows 7(.Net 4.0)でVisualStudio2010ベータ版を使用しています。

私の最初のf#プロジェクトではすべてが順調に進んでいます。まあ..ほとんどすべて。特に、次のコードを使用して、非常に単純な線形補間関数を作成しています。

let linterp (x:double) (xvalues:double list) (yvalues:double list) =
    let num_els = xvalues.Length
    if x <= xvalues.Head then 
        let result = yvalues.Head
    elif x >= (List.rev xvalues).Head then 
        let result = (List.rev yvalues).Head
    else for idx in [0 .. num_els] do 
        if List.nth xvalues idx >= x then 
            let x0 = xvalues.Item idx
            let y0 = yvalues.Item idx
            let x1 = xvalues.Item (idx+1)
            let y1 = yvalues.Item (idx+1)
            let result = y0 + (y1-y0)/(x1-x0)*(x - x0)
    result

そして、私は私の理解を完全に逃れる一連のエラーを受け取ります。

これはエラーと警告のリストです:

  • 最初、2番目、最後の「let」の「この「let」の戻り式にエラーがあります。正しいインデントの可能性があります」。

  • 「誤ったインデントの可能性:このトークンは、位置(39:10)で開始されたコンテキストのオフサイドです。このトークンをさらにインデントするか、「if」に標準のフォーマット規則を使用してみてください

  • 最後の行(結果)の「式のこのポイントまたはそれ以前の不完全な構造化コンストラクト」。

コンパイラが最初のリストを正しく推測できたので、タイプに注釈を付けるために少し汗を流さなければならなかったことを付け加えますが、2番目のリストでは、タイプは常にユニットとして推測されました。また、元のバージョン名前の結果をバインドしませんでしたが、次のように単に「式を返しました」

if x <= xvalues.Head then 
    yvalues.Head

またはで

else for idx in [0 .. num_els] do 
    if List.nth xvalues idx >= x then 
        let x0 = xvalues.Item idx
        let y0 = yvalues.Item idx
        let x1 = xvalues.Item (idx+1)
        let y1 = yvalues.Item (idx+1)
        y0 + (y1-y0)/(x1-x0)*(x - x0)

これにより、「for」の下に「この式にはタイプunitがありますが、ここではタイプdoubleで使用されています」というエラーが残り、「if」が誤ってインデントされている可能性があります。

これに対する解決策を見るとばかげていると思いますが、このような単純な問題に1時間以上も立ち往生しているので、よろしくお願いします。

前もって感謝します!

ps:[ツール]->[オプション]->....-> [F#]-> [タブ]メニューで、タブがスペースとして正しく解釈されることを確認しました

pps:これはSOに関する私の最初の質問です:-)

4

2 に答える 2

5
let linterp x (xvalues:double list) (yvalues:double list) =
    if x <= xvalues.Head then 
        yvalues.Head
    elif x >= (List.rev xvalues).Head then 
        (List.rev yvalues).Head
    else
        let idx = List.findIndex (fun e -> e >= x) xvalues
        let x0 = xvalues.Item idx
        let y0 = yvalues.Item idx
        let x1 = xvalues.Item (idx+1)
        let y1 = yvalues.Item (idx+1)
        y0 + (y1-y0)/(x1-x0)*(x - x0)
于 2009-08-20T02:07:36.117 に答える
5

あなたの問題は

let result = yvalues.Head

は完全な式ではないため、ifブロックのブランチの1つの本体を形成することはできません。for ... doループが意味のある値を返さないことを除いて、最初のアプローチは正しかった(コンパイラが説明しようとしているので、()タイプの唯一の値であるを返す。これはC#のような言語と似ている)。の代わりにunitvoidforループでは、探している値を持つ式を使用する必要があります。コードへの最小の変更は、ループで必須に設定した可変値を使用することです。より慣用的なアプローチは、List.foldのような組み込み関数を使用して、リストを単一の値に凝縮することです。これは、リスト内の連続するエントリにアクセスする必要がある(そして、xvalueとyvalueの両方を同時に操作する必要がある)という事実によって複雑になります。つまり、List.zipとSeq.pairwiseを使用する必要があります。 F#に慣れていない人の明快さを減らします。

さらに、コードをより慣用的にするために適用できる他のいくつかの変更があります。たとえば、let x0 = xvalues.Item idxより一般的にはと書かれlet x0 = xvalues.[idx]ます。ただし、F#リストは不変のリンクリストであるため、高速ランダムアクセスをサポートしていないことに注意してください。Listこれは、組み込みの演算子を使用するアプローチを好むもう1つの理由です。

于 2009-08-20T01:43:10.827 に答える