[解決済み] Haskellのprintfはどのように動作するのですか?
質問
Haskellの型安全性は2番目です。 に劣ります。 に次ぐものです。しかし Text.Printf にはいくつかの深いマジックがあり、それはむしろタイプウォンキーのようです。
> printf "%d\n" 3
3
> printf "%s %f %d" "foo" 3.3 3
foo 3.3 3
この背後にある深い魔法とは何でしょうか?どのようにして
Text.Printf.printf
関数がこのように多変数の引数を取ることができるのでしょうか?
Haskellで多変数引数を可能にするために使用される一般的なテクニックは何ですか、そしてそれはどのように動作しますか?
(余談: このテクニックを使うとき、いくつかの型安全性は明らかに失われます)。
> :t printf "%d\n" "foo"
printf "%d\n" "foo" :: (PrintfType ([Char] -> t)) => t
どのように解決するのですか?
コツは、型クラスを使うことです。の場合は
printf
の場合、キーは
PrintfType
型クラスです。これはメソッドを公開しませんが、重要な部分はとにかく型の中にあります。
class PrintfType r
printf :: PrintfType r => String -> r
そこで
printf
はオーバーロードされた戻り値の型を持っています。つまらないケースですが、余分な引数はないので、インスタンス化された
r
を
IO ()
. このために、インスタンス
instance PrintfType (IO ())
次に、可変個数の引数をサポートするために、インスタンスレベルで再帰を使用する必要があります。具体的には、もし
r
が
PrintfType
にあるように、関数型
x -> r
はまた
PrintfType
.
-- instance PrintfType r => PrintfType (x -> r)
もちろん、実際にフォーマットできる引数だけをサポートしたい。そこで、2つ目のタイプクラスである
PrintfArg
の出番です。つまり、実際のインスタンスは
instance (PrintfArg x, PrintfType r) => PrintfType (x -> r)
以下は、簡略化したもので、引数の数を問わず
Show
クラスの任意の数の引数を受け取り、それらを表示するだけの単純化されたバージョンです。
{-# LANGUAGE FlexibleInstances #-}
foo :: FooType a => a
foo = bar (return ())
class FooType a where
bar :: IO () -> a
instance FooType (IO ()) where
bar = id
instance (Show x, FooType r) => FooType (x -> r) where
bar s x = bar (s >> print x)
ここで
bar
はIOアクションを取り、引数がなくなるまで再帰的に構築され、その時点で単純に実行されます。
*Main> foo 3 :: IO ()
3
*Main> foo 3 "hello" :: IO ()
3
"hello"
*Main> foo 3 "hello" True :: IO ()
3
"hello"
True
QuickCheck も同じ手法を使用しており、ここでは
Testable
クラスには、基本ケースである
Bool
で引数を取る関数用の再帰的なインスタンスがあります。
Arbitrary
クラスの引数を取る関数のための再帰的なものです。
class Testable a
instance Testable Bool
instance (Arbitrary x, Testable r) => Testable (x -> r)
関連
-
[解決済み】なぜパースエラーになるのか?インデント?
-
[解決済み] printf ファミリーを使用して、size_t 変数をポータブルに印刷するにはどうすればよいですか?
-
[解決済み] パラメータに**(ダブルスター/アスタリスク)、*(スター/アスタリスク)がありますが、これはどういう意味ですか?
-
[解決済み] printf/String.Formatに相当するJavaScriptの機能
-
[解決済み] printfは、フォーマット文字列の中に改行がないと、呼び出し後にフラッシュしないのはなぜですか?
-
[解決済み] longをフォーマットするprintfの引数は何ですか?
-
[解決済み] printfにおけるdoubleの正しい書式指定子
-
[解決済み】boolのprintfフォーマット指定子とは?
-
[解決済み】Haskellの入門編
-
[解決済み] なぜ遅延評価が有効なのか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Haskellで "length "関数を使用しない場合のリストの長さ
-
[解決済み] Hindley-Milnerのどの部分が理解できないのでしょうか?
-
[解決済み] モナドはエンドファンクタのカテゴリではただのモノイドですが、何か問題でも?
-
[解決済み] Haskellは実世界で何に使われているのか?[クローズド]
-
[解決済み] Haskellで副作用がモナドとしてモデル化されているのはなぜですか?
-
[解決済み] レコードの単一フィールドを割り当て、残りのフィールドはコピーするための省略記法?
-
[解決済み] Emacs Interactive-Haskell repl は、cabal と working directory のいずれかが project directory に設定されると無応答になる。
-
[解決済み] Haskellのガードとif-then-elseとcaseの比較
-
[解決済み] アプリケートは合成し、モナドは合成しない
-
[解決済み] Haskell エラー 入力 `=' のパースエラー