1

n以下は、数値を受け取り、n 番目のフィボナッチ数を返すHaskell 関数です。(0 番目の数字が 0、1 番目の数字が 1、2 番目の数字が 1、3 番目の数字が 2 などのインデックス スキームを使用しました。)

fib :: (Integral a) => a -> a
fib 0 = 0
fib n = fibhelper n 0 1

fibhelper :: (Integral a) => a -> a -> a -> a
fibhelper 1 x y = y
fibhelper n x y = fibhelper (n-1) y (x+y)

さて、効率のために、Haskell の遅延評価をバイパスし、更新された引数の評価を強制したいとします ($!たとえば、演算子を使用しますか?) これを行う最もエレガントで慣用的な方法は何でしょうか?

4

1 に答える 1

8

これを行うには、バングパターンを使用できます。

{-# LANGUAGE BangPatterns #-}

fib :: (Integral a) => a -> a
fib 0 = 0
fib n = fibhelper n 0 1

-- Everything with a ! before it will be evaluated before the function body
fibhelper :: (Integral a) => a -> a -> a -> a
fibhelper 1 _ (!y) = y
fibhelper (!n) (!x) (!y) = fibhelper (n-1) y (x+y)
-- The above line is equivalent to:
--fibhelper n x y = n `seq` x `seq` y `seq` fibhelper (n-1) y (x+y)

Integral型クラスの使用に少し熱心であることにも注意してください。フィボナッチ数列のインデックスを値と同じタイプにしますか?代わりに署名を使用することをお勧めします。

fib :: (Integral a, Integral b) => a -> b

また、パフォーマンスを求めている場合は、の使用をIntegral完全に避ける必要があります。

于 2012-08-19T16:05:38.640 に答える