【问题标题】:(emulated) Macros in Haskell?(模拟)Haskell 中的宏?
【发布时间】:2010-11-20 17:06:39
【问题描述】:

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?

一个重要的编辑:我有点大错特错了。我了解我需要创建一个新列表。是否可以获取作为列表一部分的函数的参数?我想要的是能够从它们的标识符/参数组合函数,并且还能够在评估之前将函数分解为标识符/参数。

【问题讨论】:

  • 顺便说一句:你到底需要这个做什么?

标签: haskell macros lisp lazy-evaluation


【解决方案1】:

它比在 Lisp 中复杂一点,但是对于 Haskell 中的元编程,你可以使用Template Haskell

例如,[|print 1|] 将被翻译成

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

类型为Q Exp(表达式的引用)。

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

【讨论】:

    【解决方案2】:

    一旦你对函数应用了一个值,就无法取回它。尝试将函数及其参数包装在可以根据需要进行评估或分解的数据类型中。

    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
    

    【讨论】:

    • 顺便说一句,您可以使用 (print, 1) 之类的元组代替 App,使用“uncurry id”代替 runApp
    • 啊,免积分符号的乐趣。尽管如此,我还是喜欢使用特定于手头任务名称的函数
    【解决方案3】:

    你想改变列表吗?你应该回到 lisp ;-)

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

    (有一些涉及 monad 的技巧,您可以在其中模拟可变值和指针,但这可能不是您想要的。)

    编辑:不完全确定我理解编辑过的问题,但您可以将函数和参数作为数据分别处理,然后稍后“应用”,例如;

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

    【讨论】:

    • 恐怕我没有正确地提出这个问题。我真的不想改变任何东西。我希望能够在评估函数标识符/参数之前读取它们,并从通用函数/参数中编写语句。已编辑。
    【解决方案4】:

    就像有人说的那样,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
    

    【讨论】:

      猜你喜欢
      • 2017-04-10
      • 2013-03-11
      • 1970-01-01
      • 2015-09-07
      • 1970-01-01
      • 2010-09-16
      • 2017-01-11
      • 1970-01-01
      • 2013-12-25
      相关资源
      最近更新 更多