我想知道如果它是在Haskell可能定義一個函數,它當打電話給一個(無限)列表的下一個元素的下一個元素,因此,例如:的Haskell:函數,給出了一個列表
Prelude> func
1
Prelude> func
2
是否有可能在Haskell中有這樣的功能,如果有的話,你能舉個例子嗎?
我想知道如果它是在Haskell可能定義一個函數,它當打電話給一個(無限)列表的下一個元素的下一個元素,因此,例如:的Haskell:函數,給出了一個列表
Prelude> func
1
Prelude> func
2
是否有可能在Haskell中有這樣的功能,如果有的話,你能舉個例子嗎?
可以使用可變引用和IO
單子(或其他有狀態的單子)。這可以通過製造局部應用相當漂亮:
Prelude> import Data.IORef
Prelude Data.IORef> ref <- newIORef 0
Prelude Data.IORef> let func = readIORef ref >>= \r -> writeIORef ref (r+1) >> return r
Prelude Data.IORef> func
0
Prelude Data.IORef> func
1
或者更接近你的要求是什麼:
Prelude Data.IORef> ref2 <- newIORef [0..]
Prelude Data.IORef> let func2 = readIORef ref2 >>= \(x:xs) -> writeIORef ref2 xs >> return x
Prelude Data.IORef> func2
0
Prelude Data.IORef> func2
1
你可以做一個State
FUL這樣的事:
{-# LANGUAGE FlexibleContexts #-}
import Control.Monad.State
import Data.List
import Data.Maybe
-- This is not a function! The misleading name func comes from the question text.
func :: MonadState [a] m => m a
func = state (fromJust . uncons)
exampleUsage :: State [Int] (Int, Int)
exampleUsage = do
x <- func
y <- func
return (x, y)
,您可以嘗試在ghci中:
> evalState exampleUsage [1..]
(1, 2)
然而,在較高的水平,我建議重新考慮你的要求。 func
根本不是很習慣;簡單地直接使用無限列表通常會更清晰,具有較低的(語法)開銷,並且導致更好的生成代碼。例如:
exampleUsage' :: [a] -> (a, a)
exampleUsage' (x:y:_) = (x,y)
N.B.這是兩行代碼,沒有擴展或導入,與之前的11行代碼相比,包括語言擴展和三個導入。用法也簡化了;你可以完全放棄電話evalState
並完成。
> exampleUsage' [1..]
(1, 2)
也可以使用'IORef'(或類似的)。如果你對這看起來感興趣,請告訴我。 –
我同意,在大多數情況下,使用國家是很愚蠢的,而且問題的確表明這是其中的一種情況。但肯定有些情況下,與國家「職能」一起工作比直接處理無限清單更容易。例如,https://stackoverflow.com/q/41941740/625403是一個類似於這個問題,但在不同的上下文中,我的回答https://stackoverflow.com/a/41942347/625403使用狀態來跟蹤在無限列表中的位置。 – amalloy
這聽起來像你正在尋找的東西像其他語言Iterator
或Generator
結構。如果是這樣,這對於conduit庫來說似乎是一個很好的用例。請注意,有些選項(例如pipes);然而,管道可能是一個很好的起點。
如果您嘗試僅使用列表操作,則使用State
Monad可能是一個更簡單的答案(如Daniel所示);然而,如果你正在尋找一個更一般的解決方案,管道(或類似)可能確實是答案。
您正在尋找的func
因此很可能是await功能。
這裏有一個簡單的例子 -
import Prelude
import Conduit
import Data.MonoTraversable
main :: IO()
main = runConduit (source .| consume) >>= print
source :: Monad m => Producer m (Element [Integer])
source = yieldMany [0..]
consume :: Monad m => ConduitM i o m (Maybe (i, i))
consume = do
mx <- await
my <- await
return $ (,) <$> mx <*> my
,其輸出 -
λ main
Just (0,1)
通常純函數應始終返回給定相同的輸入相同的答案。所以你只能用monad來實現。 –
我試着google'ing如何做monads,但我找不到太多。你有一個想法/如何做的例子? – Coozekoek
這對我來說看起來不太好。用純函數式編程語言編程的重點是避免這種副作用,並實現參照透明。 – chi