Shake を使用しようとしていますが、次の問題に遭遇しました。文字列を補間する簡単で便利な方法はありません。私はText.Printf
について知っています—それは私が探しているものではありません。私が話している補間構文は次のとおりです:
(作る)
HEADERS_DIR := /some/path/to/dir
CFLAGS := "-g -I$(HEADERS_DIR) -O2"
(Python)
headers_dir = "/some/path/to/dir"
cflags = "-g -I{headers_dir} -O2".format(**locals())
そして、これを可能なHaskellのソリューションと比較してください。まず:
$ cabal install interpolatedstring-Perl6
$ ghci -XExtendedDefaultRules -XQuasiQuotes
その後:
> import Text.InterpolatedString.Perl6 (qq)
> let headers_dir = "/path/to/some/dir"
> [qq| -g -I$headers_dir -O2 |] :: String
Makeは、質問されなくても補間するための熱意の中で一歩進んだと思うかもしれませんが、HaskellにPythonのようなformat
関数がないのはなぜでしょうか。指定された文字列を解析し、パターンで参照されているのと同じ名前の値をプルできます。
let headers_dir = "/path/to/some/dir"
format "-g -I$headers_dir -O2"
それが実装されていない特定の理由がありますか、それともText.Printf
の冗長性や補間ライブラリの長いセットアップに誰もが満足していますか?
更新:多くの人々は、整数などの場合の精度指定の可能性がある一般的な文字列フォーマットについて尋ねる質問を誤って解釈します。提供される例は、補間の特定のケースの1つは、「名前の場所でshow a
の結果を置き換える」だけです。それはより単純な構文を考慮に入れており、それ自体は可変個関数を使用しません。
コンパイル時に文字列を補間するので、これは準クォートとして行われると思います。Haskellの関数の純粋な性質により、これは可能ですが、他の言語は不純な性質のためにそのような能力を欠いています。
考えてみてください。他の言語は、実行時に毎回それを実行する必要があります。これは、1回のコンパイル時間および準引用符で囲まれた補間よりもはるかに遅くなります。
実行時に明示的に行う場合は、Haskellの文字列がリストであることを利用するいくつかの簡単な抽象化を行うことができるはずです。または、非常に簡単に別のデータ構造を作成することもできますが、より効率的な準-私が実際に気にしたコードでこれを行っていた場合、引用されたアプローチ。
そうは言っても、C#スタイルの置換を非常に簡単に行うように見えるData.Text.FormatパッケージをHackageで見つけました。SOの例を示す答えは次のとおりです。 Haskellの文字列フォーマット -ただし、 Bryan O'Sullivanとその回答に対する他の人は、古いパッケージを使用しており、Bryanが作成した新しいパッケージがあるので(Data.Text.Formatパッケージが彼の新しいパッケージであるべきだと思います)、使用方法はわずかかもしれませんSOの例とは異なりますが、かなり似ています。
質問の更新後に更新
python version:
"-g -I{headers_dir} -O2".format(**locals())
言語の乱用です。したがって、pythonが文字列内のローカル変数補間を実際に提供しているとは言えません。実際、一部の言語ではそれが可能です。
回答why language X doesn't have feature Y
は、デザイナーが価値があるとはデザイナーが感じていなかったとしばしば言います。文字列でのローカル変数補間の場合、コマンドラインスクリプトに焦点を当てた言語で使用されるニッチなものです。どのHaskellはそうではありません。 pythonで実行できるという事実は、言語の(あまりにも)強力なリフレクション機能からのみ得られます)。
なぜText.InterpolatedString.Perl6
使用するのはとても複雑ですか?これは、Haskell言語の一部ではない準引用に依存しています。これはghc言語拡張であるため、どこかでその使用を宣言する必要があります。ライブラリのインストールと言語拡張の宣言を除外する場合、その使用法は他の例よりも複雑ではなく、より安全です。
準クォートの何が問題になっていますか?チェックアウト シェイクスピア (コメントで述べたように):
{-# LANGUAGE QuasiQuotes #-}
import Text.Shakespeare.Text
import Data.Text
runtimeInterpolatedString :: (ToText a, ToText b, ToText c) => a -> b -> c -> Text
runtimeInterpolatedString a b c = [lt|There once was #{a} that #{b} when #{c}.|]
私が提供できる最良のタイプセーフなアプローチはformatting
ライブラリです
{-# LANGUAGE OverloadedStrings #-}
import Formatting (format, (%))
import Formatting.ShortFormatters (t)
headers_dir = "/path/to/some/dir"
example = format ("-g -I" % t % " -O2") headers_dir
GHCi> example
"-g -I/path/to/some/dir -O2"
Pythonの場合:言語は、実行時に変数を名前で参照できることを実際に指定しています。 Haskell:トップレベルのバインディング以外のすべての名前は、コンパイル時に消去され、数値参照に置き換えられる傾向があります。
あなたの例では:headers_dir = "/path/to/some/dir"
は、コードが実際に実行されるまでに0x09039dc0 = "/path/to/some/dir"
に少し似たものになります。これは、headers_dir
への参照は、コンパイル時に数値参照に置き換える必要があることを意味します。これが、準クォータの目的です。
準クォータまたはテンプレートハスケルの他の部分を使用せずに;値をマップに配置するなど、変数名を手動で保存するために何かをする必要があります。