(エミュレート)Haskellのマクロ?
-
18-09-2019 - |
質問
Redditの人がこのコードを私の注意に導きました:
main = do
let ns = [print 1, print 2, print 3]
sequence_ ns
sequence_ $ reverse ns
sequence_ $ tail ns ++ [head ns]
head ns
ここで起こっているのは、リバースやテールやヘッドを手に入れるなど、私たちができることをできる操作の配列を持っていることです。
素晴らしい。
私がやりたいことは、個々の要素に入り、それらを永久に変えることです。たとえば、私はこのようなことをすることができるようになりたいです:
ns !! 0
印刷、1]のようなものを取得し、最後の要素を3.14に変更して、関数が3.14を印刷するようにします。
Haskellではまったく可能ですか、それともLispに戻る必要がありますか?
重要な編集:私はある種の失策です。新しいリストを作成する必要があることを理解しています。リストの一部である関数の引数を取得することは可能ですか?私が望んでいるのは、識別子/引数から関数を構成する能力と、評価される前に関数を識別子/引数に分割することができることです。
解決
LISPよりも少し複雑ですが、Haskellでメタプログラムするには、使用できます テンプレートhaskell.
例えば、 [|print 1|]
に翻訳されます
return $ AppE (VarE $ mkName "print") (LitE $ IntegerL 1)
タイプがあります Q Exp
(式の引用)。
あなた自身のデータを引用符にスプライスしたい場合は、 [|print $(foo 3.14)|]
実行します foo 3.14
コンパイル時に。
他のヒント
関数に値を適用したら、それを取り戻す方法はありません。ニーズに応じて、評価または分解できるデータ型で関数とその引数をラップしてみてください。
data App a b = App (a -> b) a
runApp (App a b) = a b
ns = [App print 1, App print 2, App print 3]
main = do
sequence_ $ map runApp ns
let ns2 = [App fun (arg^2) | App fun arg <- ns]
sequence_ $ map runApp ns2
出力
1
2
3
1
4
9
リストを変えたいですか?あなたはlispに戻るべきです;-)
値はHaskellで不変です。 Haskell-Wayは、最後の要素を除いて古いリストに相当する新しいリストを作成することです。
(あなたが可変値やポインターをシミュレートできるモナドを含むいくつかのトリックがありますが、それはおそらくここで望むものではありません。)
編集:編集された質問を完全に理解していませんが、機能と引数をデータとして個別に処理し、後で「適用」することができます。
do
let ns = [(print, 1), (print, 2), (print, 3)]
sequence_ $ map (\(f,a)->f a) ns
Haskell Wayは新しいリストを作成することだけであると言われているように、本当に必要な場合はio Arrayを使用してio Monad内に可変アレイを持つことができます
import Data.Array.IO
seqArr_ arr = getElems arr>>=sequence_
main= do
arr <- newListArray (0,2) [print 1,print 2,print 3] :: IO (IOArray Int (IO ()))
seqArr_ arr -- prints 1 2 3
writeArray arr 2 (print 3.14) -- change the last element
seqArr_ arr -- prints 1 2 3.14