2009-08-18 88 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