2009-08-18 14 views
15

Osoba na Reddit przyniósł ten kod do mojej uwagi:(emulowane) Makra w Haskell?

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

Co się tutaj dzieje to mamy szereg operacji, które możemy robić rzeczy ze jak rewersu lub uzyskać ogonem lub głowy.

Awesome.

Co chcę zrobić, to dostać się do poszczególnych elementów i zmienić je na dobre. Na przykład, chcę być w stanie zrobić coś takiego:

ns !! 0 

i dostać coś takiego [drukuj, 1], a następnie zmień ostatni element, powiedzmy, 3,14 tak, że funkcja będzie drukować 3.14.

Czy to możliwe w Haskell, czy powinienem po prostu wrócić do LISP-a?

AN WAŻNA EDYCJA: W pewnym stopniu popełniłem błąd. Rozumiem, że będę musiał utworzyć nową listę. Czy można uzyskać argumenty funkcji, która jest częścią listy? To, czego chcę, to możliwość komponowania funkcji z ich identyfikatorów/argumentów, a także możliwość podziału funkcji na identyfikator/argument, zanim zostanie ona oceniona.

+0

btw: czego tak naprawdę potrzebujesz? – yairchu

Odpowiedz

10

Jest to nieco bardziej skomplikowane niż w Lispie, ale do metaprogramowania w Haskell można użyć Template Haskell.

przykład [|print 1|] będą tłumaczone

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

który ma typ Q Exp (przytoczenia wyrażeniu).

Jeśli chcesz połączyć własne dane w ofertę, [|print $(foo 3.14)|] wykona foo 3.14 podczas kompilacji.

4

Chcesz zmutować listę? Powinieneś wrócić do selekcji ;-)

Wartości są niezmienne w Haskell. Sposób Haskella polega na utworzeniu nowej listy, która jest odpowiednikiem starej listy z wyjątkiem ostatniego elementu.

(Istnieją pewne sztuczki polegające monads gdzie można symulować wartości zmienne i wskaźniki, ale to nie jest chyba to, co chcesz tutaj.)

EDIT: Nie jest całkowicie pewien, czy rozumiem pytanie edytowany, ale można traktuje funkcję i argument oddzielnie jako dane, a następnie "stosuje" później, np .;

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

Obawiam się, że nie sformułowałem poprawnie pytania. Naprawdę nie chcę niczego mutować. Chcę móc odczytać identyfikator/argumenty funkcji przed ich oceną, a także tworzyć instrukcje z ogólnych funkcji/argumentów. Edytowano. – mannicken

11

Po zastosowaniu wartości do funkcji nie można jej odzyskać. Spróbuj zawinąć funkcję i jej argument w typie danych, który możesz ocenić lub rozłożyć w zależności od potrzeb.

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 

Wyjścia

1 
2 
3 
1 
4 
9 
+0

btw, możesz używać krotek takich jak (print, 1) zamiast App i "uncurry id" zamiast runApp – yairchu

+0

Ah, radości zapisu bez punktów. Mimo to lubię mieć funkcje z nazwami specyficznymi dla danego zadania –

1

Jak zostało powiedziane sposób Haskell jest po prostu utworzyć nową listę, ale można mieć zmienny tablice wewnątrz monady IO z IOArray jeśli naprawdę chcesz

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