(emulado) Macros em Haskell?
-
18-09-2019 - |
Pergunta
Uma pessoa no Reddit trouxe este código a minha atenção:
main = do
let ns = [print 1, print 2, print 3]
sequence_ ns
sequence_ $ reverse ns
sequence_ $ tail ns ++ [head ns]
head ns
O que está acontecendo aqui, é que nós temos uma matriz de operações que podemos fazer coisas, como reverter ou obter a sua cauda ou a cabeça.
Impressionante.
O que eu quero é chegar em elementos individuais e alterá-las para o bem.Por exemplo, eu quero ser capaz de fazer algo como isto:
ns !! 0
e obter algo como [print, 1] e, em seguida, altere o último elemento, digamos, 3.14, de modo a que a função de impressão 3.14.
É possível, no Haskell, ou devo apenas voltar para o LISP?
UMA IMPORTANTE EDIÇÃO:Eu meio que errou.Eu entendo que eu preciso para criar uma nova lista.É possível obter os argumentos de uma função, que é uma parte de uma lista?O que eu quero é a capacidade de compor funções de seus identificadores/argumentos e também ser capaz de quebrar uma função de identificador/argumento antes que ele seja avaliado.
Solução
É um pouco mais complicado do que em Lisp, mas para metaprogramação em Haskell, você pode usar Modelo Haskell.
Por exemplo, [|print 1|]
será traduzido para
return $ AppE (VarE $ mkName "print") (LitE $ IntegerL 1)
que tem o tipo Q Exp
(uma citação de uma expressão).
Se você deseja conspirar seus próprios dados em uma cotação, [|print $(foo 3.14)|]
será executado foo 3.14
em tempo de compilação.
Outras dicas
Depois de aplicar um valor a uma função, não há como recuperá -lo. Tente envolver a função e seu argumento em um tipo de dados que você pode avaliar ou decompor, dependendo de suas necessidades.
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
Saídas
1
2
3
1
4
9
Você quer transformar a lista?Você deve voltar para lisp ;-)
Os valores são imutáveis em Haskell.O Haskell-forma é criar uma nova lista, que é equivalente à lista de idade, exceto para o último elemento.
(Existem alguns truques envolvendo mônadas, onde você pode simular valores mutáveis e os ponteiros, mas que provavelmente não é o que você quer aqui.)
EDITAR:Não totalmente certo, eu entendo o editado pergunta, mas você pode lidar com função e argumento separadamente, como dados e, em seguida, "aplicar" e, mais tarde, por exemplo.;
do
let ns = [(print, 1), (print, 2), (print, 3)]
sequence_ $ map (\(f,a)->f a) ns
Como já foi dito o asclock, uma maneira é criar uma nova lista, mas você pode ter mutável matrizes dentro do IO mônada com IOArray se você realmente quer
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