3 に答える
David V. リンクありがとうございます。Repr
ツールボックスに追加する価値は間違いありません。便利だと思ったライブラリをいくつか追加したいと思います。
HackageDB : Trace (2010 年 12 月 12 日現在)
- ghc-events ライブラリとプログラム: GHC の .eventlog ファイルを解析するためのライブラリとツール
- hood ライブラリ: 現場観察によるデバッグ
- hpc-strobe ライブラリ: 実行中の Haskell プログラム用に Hpc が生成したストローブ
- hpc-tracer プログラム: AJAX インターフェイスを備えたトレーサー
Hook パッケージは、私が探しているもののようです。後日、さらにサンプルを投稿します。
main = runO ex9
ex9 = print $ observe "foldl (+) 0 [1..4]" foldl (+) 0 [1..4]
出力
10
-- foldl (+) 0 [1..4]
{ \ { \ 0 1 -> 1
, \ 1 2 -> 3
, \ 3 3 -> 6
, \ 6 4 -> 10
} 0 (1 : 2 : 3 : 4 : [])
-> 10
}
私は Hackage ライブラリを知りませんでした (Haskell を始めたばかりなので)。Perl の CPAN を思い出します。それらのリンクを提供していただきありがとうございます。これは素晴らしいリソースです。
これはあなたの質問に対する完全な回答ではありませんが、Haskell-Cafeでいくつかの回答がある会話を見つけました:
http://www.haskell.org/pipermail/haskell-cafe/2010-June/078763.html
そのスレッドはこのパッケージにリンクしています:
http://hackage.haskell.org/package/reprこのページによると、「オーバーロードされた式をテキスト表現にレンダリングできる」
提供される例は次のとおりです。
*Repr> let rd = 1.5 + 2 + (3 + (-4) * (5 - pi / sqrt 6)) :: Repr Double
*Repr> show rd
"fromRational (3 % 2) + 2 + (3 + negate 4 * (5 - pi / sqrt 6))"
これは質問されていない質問への回答です。長いコメントと考えてください。
(適合しないと思われる場合は、0未満でのみ反対票を投じてください。それでは削除します。)
もう少し経験を積むとすぐに、物事がどのように拡大するかを見たくないかもしれません。物事がどのように機能するかを理解する必要があります。それは、なぜそれが機能するのかという質問に取って代わります。それがどのように拡大するかを観察するだけでは、もはや多くを得ることができません。
コードを分析する方法は、想像するよりもはるかに簡単です。因果関係の進行に応じて、すべてのパラメーター/変数に「評価済み」、「未評価」、または「評価予定」のいずれかのラベルを付けるだけです。
2つの例:
1.)fibs
すべてのフィボナッチ数のリストは
fibs :: (Num a) => [a]
fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
最初の2つの要素はすでに評価されています。したがって、3番目の要素(値2)に評価対象のラベルを付け、残りはすべて未評価のラベルを付けます。3番目の要素は、フィブの最初の要素とテールフィブの(+)-組み合わせになります。これは、すでに評価済みとしてラベル付けされているフィブの1番目と2番目の要素になります。これは、評価対象のn番目の要素と、すでに評価されている(n-2)-ndおよび(n-1)-stの要素でそれぞれ機能します。
これはさまざまな方法で視覚化できます。
fibs!!(i+0)
+ fibs!!(i+1)
= fibs!!(i+2)
(fibs)
zipWith(+) (tail fibs)
= (drop 2 fibs)
1 : 1 : 2 : 3 ...
(1 :)1 : 2 : 3 : 5 ...
(1 : 1 :)2 : 3 : 5 : 8 ...
2.)あなたの例「ふるい(p:ps)xs」
primes = 2: 3: sieve (tail primes) [5,7..]
where
sieve (p:ps) xs = h ++ sieve ps [x | x <- t, rem x p /= 0]
-- or: filter ((/=0).(`rem`p)) t
where (h,~(_:t)) = span (< p*p) xs
「ふるい(p:ps)xs」では、
- pが評価され、
- psは未評価であり、
- xsは、評価された無限の部分的にふるいにかけられたリスト(pを含まないが、p²を含む)であり、再帰を読んだり、hの値が素数である必要があることを認識したりすることができます。
Sieveはpの後に素数のリストを返す必要があるため、少なくとも次の素数が評価されます。
- 次の素数はリストhにあります。これは、すべての(すでにふるいにかけられた)数kのリストです。ここでp<k<p²; xsにはpも、pより下の素数で割り切れる数も含まれていないため、hには素数のみが含まれます。
- tには、p²より上のxsのすべての数が含まれます。hのすべての要素を評価する必要さえないかもしれないので、tはできるだけ早くではなく怠惰に評価されるべきです。(hの最初の要素のみが評価されます。)
関数定義の残りの部分は再帰であり、次のxsはtであり、すべてのn*pがふるいにかけられます。
foldrの場合、分析により、「go」は実行時間を高速化するためにのみ定義されており、読みやすさは定義されていないことが示されます。分析が簡単な別の定義を次に示します。
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr (.:) e (x:xs) = x .: (foldr (.:) e xs)
foldr (.:) e [] = e
ここでその機能について説明しました(分析なし)。
このタイプの分析をトレーニングするには、いくつかの標準ライブラリのソースを読むことをお勧めします。つまり、Data.Listのソースにあるscanl、scanr、 unfoldrです。