views:

291

answers:

4

Hi.

A person on Reddit has brought this code to my attention:

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

What's going on here is we have an array of operations that we can do stuff with, like reverse or get its tail or head.

Awesome.

What I want to do is get into individual elements and change them for good. For example, I want to be able to do something like this:

ns !! 0

and get something like [print, 1] and then change last element to, say, 3.14 so that the function would print 3.14.

Is it at all possible in Haskell or should I just go back to LISP?

AN IMPORTANT EDIT: I sort of blundered. I understand that I will need to create a new list. Is it possible to get the arguments of a function, which is a part of a list? What I want is the ability to compose functions from their identifiers/arguments and also be able to break down a function into identifier/argument before it gets evaluated.

+4  A: 
JacquesB
I am afraid I didn't formulate the question correctly. I don't really want to mutate anything. I want to be able to read function identifier/arguments before they get evaluated and also compose statements from generic functions/arguments.Edited.
mannicken
+9  A: 

Once you've applied a value to a function, there's no way to get it back. Try wrapping the function and its argument in a datatype that you can evaluate or decompose depending on your needs.

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

Outputs

1
2
3
1
4
9
jleedev
btw, you can use tuples like (print, 1) instead of App and "uncurry id" instead of runApp
yairchu
Ah, the joys of points-free notation. Still, I like having functions with names specific to the task at hand
jleedev
+1  A: 

Like has been said the haskell way is to just create a new list, but you can have mutable arrays inside the IO monad with IOArray if you really want

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
hiena
+6  A: 

It is a bit more complicated than in Lisp, but for metaprogramming in Haskell, you can use Template Haskell.

E.g., [|print 1|] will be translated to

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

which has the type Q Exp (a quotation of an expression).

If you want to splice your own data into a quotation, [|print $(foo 3.14)|] will execute foo 3.14 at compile-time.

Alexey Romanov