Reddit上的一个人引起了我的注意:
main = do
let ns = [print 1, print 2, print 3]
sequence_ ns
sequence_ $ reverse ns
sequence_ $ tail ns ++ [head ns]
head ns
这里发生的事情是我们有一系列的操作,我们可以做的事情,如反向或得到它的尾巴或头。
真棒。
我想要做的是进入个别元素并改善它们。例如,我希望能够做到这样的事情:
ns !! 0
并获得类似[print,1]的内容,然后将最后一个元素更改为3.14,以便该函数打印3.14。
在Haskell中是否完全可以,或者我应该回到LISP?
重要编辑:我有点失误。我知道我需要创建一个新列表。是否有可能获得函数的参数,这是列表的一部分?我想要的是能够从标识符/参数中组合函数,并且能够在评估之前将函数分解为标识符/参数。
答案 0 :(得分: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
答案 1 :(得分:11)
它比Lisp复杂一点,但对于Haskell中的元编程,你可以使用Template Haskell。
例如,[|print 1|]
将被翻译为
return $ AppE (VarE $ mkName "print") (LitE $ IntegerL 1)
,其类型为Q Exp
(表达式的引用)。
如果您想将自己的数据拼接成引号,[|print $(foo 3.14)|]
将在编译时执行foo 3.14
。
答案 2 :(得分:4)
你想改变名单吗?你应该回到lisp; - )
值在Haskell中是不可变的。 Haskell方式是创建一个新列表,除了最后一个元素之外,它等同于旧列表。
(有一些涉及monad的技巧,你可以模拟可变的值和指针,但这可能不是你想要的。)
编辑:我不完全确定我理解编辑过的问题,但您可以将函数和参数分别作为数据处理,然后再“应用”,例如。
do
let ns = [(print, 1), (print, 2), (print, 3)]
sequence_ $ map (\(f,a)->f a) ns
答案 3 :(得分:1)
就像已经说过的那样,haskell的方法就是创建一个新的列表,但如果你真的想要的话,你可以在IO monad中使用IOArray创建可变数组
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