2009-07-10 8 views
3

オイラー問題のいくつかを調べることでF#を学習しようとしています。見つけ出す。これは私の素朴な解決策です。私はこれを行うとF#:警告FS0020:この式は 'unit'タイプである必要がありますが、タイプは 'bool'です。

let compute = 
    let mutable f = false 
    let mutable nr = 0 
    while f = false do 
     nr <- nr + 20 
     f = checkMod nr 
    nr 

私はFS0020を警告するエラーメッセージが表示されます。この式は、型「ユニット」を持っているはずですが、表現上の「NR <を - 20 NR」「ブール」を入力しています。私は書き直して、式を動かしてみました。そして、私はいつもwhileステートメントの下の行にそのエラーを出します。

私はVS2010 Betaを使ってこれを書いています。

答えて

10

次の行:私はあなたが意図していると考えているよう

f = checkMod nr 

は平等のチェックではなく、割り当てです。それを次のように変更してください:

f <- checkMod nr 

すべてが正常に動作するはずです。私はなぜ前の行に正しい構文を使用したのか分かりません。

また、while f = false doの行は実際にwhile not f doに簡略化する必要があります。ブール値の平等チェックはむしろ複雑です。

私は、あなたが命令的言語としてF#を効果的に使用しようとしていることを指摘する必要があると感じています。可変の変数とwhileループの使用は、関数的言語(F#を含む)では強く推奨されません。特にこのような純粋に機能的な(より単純な)ソリューションが存在する場合にはそうです。私はあなたが機能的なスタイルのプログラミングについて少し読むことをお勧めします。もちろん、シンタックスを把握するだけでは、それ自体にとっては便利なことです。

+0

問題を解決したおかげで、私はそう長くのためにそれを見つめた後:) 私の目標は、関数型プログラミングのスタイルを学ぶことですが、勉強には少し時間と、それは非常に遅いだと逃した信じることができませんプロセス。 – Paxxi

+0

ええ、十分に公正。関数型プログラミングは、以前は命令型言語(例えばC/C#/ Java)のみを行っていたコーダーにとって大きなショックとなることがあります。時間の経過とともに学ぶことができる、まったく異なる思考方法が必要です。 – Noldorin

+0

しかし、F#の素晴らしい点の1つは、おなじみのコーディングスタイル(無条件)から始めることができ、まだ生産的である間にfuntional mindesetに容易にできることです。 –

0

while expressions(F#で)あなたが命令的言語から来ている場合、少し慣れています。 while式の各行は、unit(C++/C#のvoidと考える)に評価されなければなりません。全体的な表現はまた、unitと評価されます。例で

Noldorinに述べたように

f = checkMod nr 

boolと評価一方

nr <- nr + 20 

unitに評価されます。この結果、警告メッセージが報告されます。あなたが望むなら実際に警告を消すことができます。ファイルの先頭に次のように入力してください:

#nowarn "0020" 
1

機能スタイルを採用しようとする場合は、変更可能な値を避けてください。

let nr = 
    let rec compute nr = 
     if checkMod nr then nr else compute (nr + 20) 
    compute 0  
12

私は警告FS0020に関する情報を調べるための「標準的な」場所になってきて、このWEGページを想像することができるので、ここでは3最も一般的な例私の簡単な要約があります:このような例

警告が表示され、修正方法が表示されます。

意図的にのみ、その副作用のために呼び出される関数の結果を破棄:

// you are calling a function for its side-effects, intend to ignore result  
let Example1Orig() = 
    let sb = new System.Text.StringBuilder() 
    sb.Append("hi")  // warning FS0020 
    sb.Append(" there") // warning FS0020 
    sb.ToString() 

let Example1Fixed() = 
    let sb = new System.Text.StringBuilder() 
    sb.Append("hi") |> ignore 
    sb.Append(" there") |> ignore 
    sb.ToString() 

警告(関数は全く効果がない)エラーを指摘し、有用である:

// the warning is telling you useful info 
// (e.g. function does not have an effect, rather returns a value) 
let Example2Orig() = 
    let l = [1;2;3] 
    List.map (fun x -> x * 2) l // warning FS0020 
    printfn "doubled list is %A" l 

let Example2Fixed() = 
    let l = [1;2;3] 
    let result = List.map (fun x -> x * 2) l 
    printfn "doubled list is %A" result 

混同している代入演算子と等価比較演算子:

// '=' versus '<-' 
let Example3Orig() = 
    let mutable x = 3 
    x = x + 1   // warning FS0020 
    printfn "%d" x  

let Example3Fixed() = 
    let mutable x = 3 
    x <- x + 1 
    printfn "%d" x  
+0

このエラーを得るもう一つの方法はダッシュを忘れることです:x < - x + 1ではなくx Jackson

0

私は長い間、命令的なスタイルでプログラミングしてきたので、機能プログラミングの考え方に慣れていました。

この例では、checkModテストに合格した20の最初の倍数を探しています。これはの部分です。部分です。機能については、の部分については、シーケンスで利用できるメソッドを参照することをお勧めします。

let multi20 = Seq.initInfinite (fun i -> i*20) 
let compute = multi20 |> Seq.find checkMod 

最初のletはtwentyplesの無限のリストを生成します(私は1つを作った):何が必要この様配列の最初の要素(20の倍数)テストに合格、です。 2番目のletは、テストに合格したリストの最初の番号を見つけます。あなたの仕事は、テストに合格する番号が実際にあることを確認することですが、それはもちろん命令的なコードにも当てはまります。

あなたは1に2本の以上のラインを凝縮したい場合は、

let computeCryptic = Seq.initInfinite ((*) 20) |> Seq.find checkMod 

を書くことができますが、私は数週間後、それを読み取ろうとする際に、コードにそのようなスタントを引っ張っすると頭痛につながることができますを見つけます。

0

ブライアンの記事と同じ趣旨で、警告FS0020を取得する別の方法があります。一言で言えば、私は誤って関数の引数をタプルしました。

2番目の行(gdp ...)で警告が表示された、以下のコードをデバッグするのは困難でした。FS0020:この式は 'unit'タイプである必要がありますが、 '文字列 - >^a - >単位)*文字列*浮動小数点型その線はまったく問題ではないことが判明しました。代わりに、それは台無しにされたprintfn行でした。コンマ区切り記号を引数リストから削除すると、それが修正されました。

for country in wb.Regions.``Arab World``.Countries do 
    let gdp = country.Indicators.``GDP per capita (current US$)``.[2010] 
    let gdpThous = gdp/1.0e3 
    printfn "%s, %s (%.2f)" country.Name, country.CapitalCity, gdpThous 
関連する問題