go
Haskellの資料や情報源を読んでいるとよく見かけますが、それについて本当に快適に感じることはありませんでした-(私の心の中には「goto」という否定的な意味合いがあると思います)。私はLYAHでHaskellのを学び始め、そして私が使用する傾向を拾いのことacc
とstep
するときは、折り目を書きます。書くための慣習はどこgo
から来たのですか?
最も重要なことは、その名前が正確に何go
を意味するのでしょうか?
go
Haskellの資料や情報源を読んでいるとよく見かけますが、それについて本当に快適に感じることはありませんでした-(私の心の中には「goto」という否定的な意味合いがあると思います)。私はLYAHでHaskellのを学び始め、そして私が使用する傾向を拾いのことacc
とstep
するときは、折り目を書きます。書くための慣習はどこgo
から来たのですか?
最も重要なことは、その名前が正確に何go
を意味するのでしょうか?
go
私が読んだHaskellの資料では見たことがありません。例/参考資料を教えてください。
回答:
うーん!いくつかの考古学!
2004年頃からgo
、再帰関数のワーカー/ラッパー変換を行うときに、末尾再帰ワーカーループの総称として使用してきました。私はそれを広く使い始めましたbytestring
、例えば
foldr :: (Word8 -> a -> a) -> a -> ByteString -> a
foldr k v (PS x s l) = inlinePerformIO $ withForeignPtr x $ \ptr ->
go v (ptr `plusPtr` (s+l-1)) (ptr `plusPtr` (s-1))
where
STRICT3(go)
go z p q | p == q = return z
| otherwise = do c <- peek p
go (c `k` z) (p `plusPtr` (-1)) q -- tail recursive
{-# INLINE foldr #-}
からでした bytestring
2005年8月。
これはRWHで書かれ、おそらくそこから普及したのでしょう。また、ストリームフュージョンではライブラリでは、DuncanCouttsと私はそれをたくさんやり始めました。
GHCソースから
しかし、イディオムはさらに遡ります。foldr
GHC.Baseでは次のように与えられます:
foldr k z = go
where
go [] = z
go (y:ys) = y `k` go ys
これはおそらく私がトリックを拾った場所です(これはAndy Gillの論文からのものだと思いましたが、go
そこでの使用法は見つかりませんでした)。そうではありませんGoferにこの形式で与えられたので、私はこれが最初のGHCのコードベースに登場だと思います。
2001年、サイモン・マーローは使用していたgo
システムレベルのコードの一部では、私たちは、に私たちをGHCで非難のどこかに置いて、この手掛かりリードかもしれないGHCソース、go
広く労働者の機能に使用されます。
myCollectBinders expr
= go [] expr
where
go bs (Lam b e) = go (b:bs) e
go bs e@(Note (SCC _) _) = (reverse bs, e)
go bs (Cast e _) = go bs e
go bs (Note _ e) = go bs e
go bs e = (reverse bs, e)
GHC3.02およびグラスゴー
古いバージョンのGHCを掘り下げると、GHC 0.29ではこのイディオムは表示されませんが、GHC 3.02シリーズ(1998)では、このgo
イディオムはどこにでも表示されます。のNumeric.lhs
定義におけるshowInt
、1996年から1997年の日付の例:
showInt n r
| n < 0 = error "Numeric.showInt: can't show negative numbers"
| otherwise = go n r
where
go n r =
case quotRem n 10 of { (n', d) ->
case chr (ord_0 + fromIntegral d) of { C# c# -> -- stricter than necessary
let
r' = C# c# : r
in
if n' == 0 then r' else go n' r'
}}
これは、H98レポートに記載されているものとは異なる実装です。ただし、「Numeric.lhs」の実装を掘り下げると、1997年にGHC 2.06に追加されたバージョンと同じではないことがわかり、1998年4月にSigbjorneFinneからの非常に興味深いパッチが追加されました。go
Numeric.lhsにループします。
これは、少なくとも1998年までに、Sigbjorneがgo
GHCの「std」ライブラリにループを追加し、同時にGHCコンパイラコアの多くのモジュールにgo
ループがあったことを示しています。さらに掘り下げてみると、1996年7月のWill Partainによるこの非常に興味深いコミットにより、GHCに「go」ループが追加されます。コードはSimonPJからのものです。
だから私はこれを、サイモン・マーロウ、シグビョルン・フィン、ウィル・パーテン、サイモン・ペイトン・ジョーンズなど、90年代半ばにGHCに取り組んだグラスゴーの人々によって発明されたグラスゴーのイディオムと呼ぶことにします。
f
、私は通常f'
、この種のものの名前として使用go
しますが、一種のキーワードに近いイディオムとして使用することは、私が理解しようとするものです。showInt
同じガードを複数回評価することを避けるためにイディオムを使用していることに注意してください。
goto
、そしてヘルパー関数に制御を引き渡すことを示唆していると言うでしょう。
loop
すでにgo
規則を使用しているコードを変更しない限り、私は使用する傾向があります。「ループを回る」のように、文字通り「行く」という意味だといつも思っていました。
明らかにドンの答えは正しいものです。少し詳しく説明します(あなたが直接参照しているのは私の文章のようですので):goは2文字しかないのでいいです。
ああ、そして、Yesodの本が列挙子パッケージに多くのコンテンツを捧げている理由は、私がすでに列挙子の3部構成のチュートリアルをブログ投稿シリーズとして書いているので、それを本に含めるほうがよいと決めたからです。列挙子パッケージは、Yesod全体のさまざまな場所で使用されているため、関連性があります。
このイディオムは、線形構造(したがって「ループ」)だけでなく、分岐(ツリーのような)構造にも適用できると思います。
go
パターンが累積パラメーターに対応する頻度、より一般的には、Mitch Wandが論文「継続ベースのプログラム変換戦略」(私のお気に入りの論文の1つ)で調査した継続エンコード戦略に対応する頻度はどれくらいか疑問に思います。このような場合、go
関数には特定の意味があり、エレガントな仕様から効率的なコードを導出するために使用できます。
add_x
またはのようなものconsOnto_xs
。
loop
代わりに関数を呼び出します。