2009-08-18 57 views
15

Reddit上的人带来了这个代码了我的注意:(模拟)Haskell中的宏?

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吗?

一个重要的编辑:我有点失控。我知道我需要创建一个新列表。是否有可能获得函数的参数,这是列表的一部分?我想要的是能够从它们的标识符/参数组成功能,并且能够在评估之前将功能分解为标识符/参数。

+0

btw:你究竟需要什么? – yairchu 2009-08-18 21:02:08

回答

10

这比Lisp复杂一些,但对于Haskell中的元编程,您可以使用Template Haskell

例如,[|print 1|]将被转换为

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

其具有类型Q Exp(表达式的报价)。

如果您想将自己的数据拼接成报价,[|print $(foo 3.14)|]将在编译时执行foo 3.14

4

你想改变列表吗?你应该回去诽谤;-)

值在Haskell中是不可变的。 Haskell方式是创建一个新的列表,除了最后一个元素外,它与旧列表相同。

(有涉及单子,你可以模拟可变值和指针一些技巧,但是这可能不是你想要的这里。)

编辑:不能完全确定我理解编辑的问题,但你可以将函数和参数作为数据单独处理,然后稍后“应用”,例如。

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

恐怕我没有正确地制定问题。我真的不想改变任何东西。我希望能够在函数标识符/参数得到评估之前读取它们,并且还可以编写泛型函数/参数的语句。 已编辑。 – mannicken 2009-08-18 20:07:12

11

一旦你给一个函数应用了一个值,就没有办法让它恢复。尝试将函数及其参数封装在可根据需要评估或分解的数据类型中。

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 
+0

顺便说一句,你可以使用像元素(打印,1)而不是应用程序和“uncurry id”而不是runApp – yairchu 2009-08-18 21:58:01

+0

啊,点免费乐谱的乐趣。尽管如此,我还是喜欢用特定的名字来完成任务 – 2009-08-19 08:31:50

1

就像一直说Haskell的办法是只创建一个新的列表,但你可以有IOArray的IO单子里面可变数组,如果你真的想

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