2012-01-24 11 views
9

私は積分する区間の終点の引数a、bを取る反微分を返して、台形則を使ってHaskellで関数を数値的に積分しようとしています。上記でHaskell:where句はラムダの束縛変数を参照しています

integrate :: (Float -> Float) -> (Float -> Float -> Float) 

integrate f 
    = \ a b -> d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b) 
    where 
     d = (b - a)/n 
     n = 1000 

、私は

n - for the number of subintervals 
d - for the width of each subinterval 

これを使用し、ほぼラムダ中の結合の引数、Bを除き、動作します。私は エラーメッセージが出ます:

Not in scope: `b' 
Not in scope: `a' 

を私は(の範囲は、bはちょうどそのラムダ式に制限されないが、私は記述する必要はありませんように はHaskellでは回避策は存在していることを理解することができますba)/ nは上記のdの出現ごとに?

+4

TIL:あなたが使用することはできません 'WHERE'ラムダと[VSどこましょう](のhttp:/ /www.haskell.org/haskellwiki/Let_vs._Where)。また参照してください[Where'節はHaskellで便利になるでしょう](http://stackoverflow.com/questions/6032183/where-does-the-where-clause-come-in-handy-in-haskell) – rampion

+0

答えた人のおかげです。私はこの問題がよく知られているlet vs discussionに直接つながっていることに気付かなかった。私は、関数を以下のように書くことを提案した人にも感謝したいと思います:integrate f a b = ...それはうまく簡潔な解決策です。 – Bylextor

答えて

1

試してみてください。

integrate f a b = d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b) 
    where 
     d = (b - a)/n 
     n = 1000 
16

あなたは2 Float秒を取り、Floatを返す関数を返す必要が考えているが、実際にそれがあなたのintegrate機能に2つの余分なFloatの引数を取り、使用に何ら変わりませんカリング(つまり、それらを提供しないでください。戻り値の型はFloat -> Float -> Floatになります)。

だから、この

integrate :: (Float -> Float) -> Float -> Float -> Float 

integrate f a b 
    = d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b) 
    where 
     d = (b - a)/n 
     n = 1000 

それとも、代わりにwherelet ... inを使用することができますようにあなたの関数を書き換えることができます。

integrate f 
    = \a b -> 
     let d = (b - a/n) 
      n = 1000 
     in d * sum [ f (a + d * k) | k <- [0..n] ] - d/2.0 * (f a + f b) 
+2

FWIW、Matthewは型シグネチャのカッコを省略していますが、これは必須ではありません。型シグネチャを同じように保ち、この新しい方法で関数本体を書くことができます。 2つの署名は*正確に等価です。 – luqui

+0

よく見つかる。私は答えを書いていたときに私は忘れてしまったのではないことを言いたいと思っていました。おかげさまで –

+0

積分f a b = ...として関数を書き直すことは最適な解決法です。 – Bylextor

4

確かに。あなたはどこに主張する場合

integrate f a b = d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b) 
    where 
     d = (b - a)/n 
     n = 1000 
2

integrate f = \a b -> case() of 
    () -> d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b) 
      where 
       d = (b - a)/n 
       n = 1000 

はかなり良さそうだが、それをしないのですか? は、ケースはもう少しやる気に見えるようにするには:

integrate f = \a b -> case (f a + f b) of 
    fs -> d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * fs 
      where 
       d = (b - a)/n 
       n = 1000 
+0

非常に賢い!ありがとうございました! – Bylextor

3

あなたは回避策がたくさんあります。

あなたはラムダ式を除く任意の結合構文がわからない場合、あなたがこれを行うことができます(私は、その理論的な美しさを最も愛しているが、その構文上の醜さを使用することはありませんどの):

integrate f 
    = \a b -> (\d -> d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b)) 
      ((b - a)/n) 
    where 
     n = 1000 

の場合

integrate f = go 
    where 
    n = 1000 
    go a b = d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b) 
     where 
     d = (b - a)/n 

あなたもlet -syntaxを知っている場合は、あなたがこれを行うことができます:

を定義し、唯一のあなたがこれを行うことができ-syntax whereを知っているあなたのような
integrate f = 
    \a b -> let d = (b - a)/n 
      in d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b) 
    where 
    n = 1000 

あなたはa -> (b -> c -> d)a -> b -> c -> dと同じであることを覚えていれば最後に、あなたが明白な操作を行うことができます。

integrate f a b = d * sum [ f (a + d*k) | k <- [0..n] ] - d/2.0 * (f a + f b) 
    where 
    n = 1000 
    d = (b - a)/n 
+1

最初のオプションを使用しない別の理由があります:lambdasは多型を許可しません。 – luqui

+0

ありがとうございます。 letオプションはおそらく私のバウンド変数問題の最も簡単な回避策です。 – Bylextor

+0

「行く」についてもう少し教えていただけますか?私はそれを調べようとしましたが、検索エンジンが通常の英語の単語 "go"と混同し、 "go"がほとんどのブックインデックスに表示されないため、Haskellで "go"に関する情報を見つけるのは非常に困難です。 – Bylextor

関連する問題