2009-08-18 14 views
15

Una persona en Reddit ha traído este código a mi atención:(emulado) ¿Macros en Haskell?

main = do 
    let ns = [print 1, print 2, print 3] 
    sequence_ ns 
    sequence_ $ reverse ns 
    sequence_ $ tail ns ++ [head ns] 
    head ns 

lo que está pasando aquí es que tenemos una serie de operaciones que podemos hacer cosas con, como inversa o conseguir su cola o la cabeza.

Impresionante.

Lo que quiero hacer es entrar en elementos individuales y cambiarlos para siempre. Por ejemplo, quiero ser capaz de hacer algo como esto:

ns !! 0 

y conseguir algo como [imprimir, 1] y luego cambiar a último elemento, por ejemplo, 3,14 para que la función imprimiría 3.14.

¿Es posible en Haskell o debería volver a LISP?

UNA EDICIÓN IMPORTANTE: En cierto modo cometí un error. Entiendo que tendré que crear una nueva lista. ¿Es posible obtener los argumentos de una función, que es parte de una lista? Lo que quiero es la capacidad de componer funciones a partir de sus identificadores/argumentos y también poder descomponer una función en identificador/argumento antes de que se evalúe.

+0

por cierto, ¿para qué necesitas esto en realidad? – yairchu

Respuesta

10

Es un poco más complicado que en Lisp, pero para la metaprogramación en Haskell, puede usar Template Haskell.

por ejemplo, [|print 1|] se traducirán a

return $ AppE (VarE $ mkName "print") (LitE $ IntegerL 1) 

que tiene el tipo de Q Exp (una cita de una expresión).

Si desea empalmar sus propios datos en una cita, [|print $(foo 3.14)|] ejecutará foo 3.14 en tiempo de compilación.

4

¿Deseas mutar la lista? Deberías volver a lisp ;-)

Los valores son inmutables en Haskell. La manera Haskell es crear una nueva lista que es equivalente a la lista anterior, excepto por el último elemento.

(Hay algunos trucos que implican mónadas donde se puede simular valores mutables y punteros, pero eso no es probablemente lo que usted quiere aquí.)

EDIT: No del todo seguro de entender la pregunta editado, pero se puede manejar la función y el argumento por separado como datos y luego "aplicar" más tarde, por ejemplo;

do 
    let ns = [(print, 1), (print, 2), (print, 3)] 
    sequence_ $ map (\(f,a)->f a) ns 
+1

Me temo que no formulé la pregunta correctamente. Realmente no quiero mutar nada. Quiero poder leer los identificadores/argumentos de funciones antes de que se evalúen y también redactar declaraciones de funciones/argumentos genéricos. Editado. – mannicken

11

Una vez que haya aplicado un valor a una función, no hay forma de recuperarla. Intente ajustar la función y su argumento en un tipo de datos que pueda evaluar o descomponer según sus necesidades.

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 

salidas

1 
2 
3 
1 
4 
9 
+0

Por cierto, puede utilizar tuplas como (imprimir, 1) en lugar de la aplicación y "no registrar ID" en lugar de ejecutar – yairchu

+0

Ah, las alegrías de la notación sin puntos. Aún así, me gusta tener funciones con nombres específicos para la tarea en cuestión –

1

Como se ha dicho la forma en Haskell es simplemente crear una nueva lista, pero puede tener matrices mutables dentro de la mónada IO con IOArray si realmente quiere

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