看起來@Benjamin Hodgson誤讀了您的問題,並認爲您希望f
適用於每個部分結果中的單個元素。正因爲如此,你最終認爲他的方法並不適用於你的問題,但我認爲它確實如此。考慮下面的變型:
import Control.Monad.State
indexed :: (Traversable t) => t a -> (t (Int, a), Int)
indexed t = runState (traverse addIndex t) 0
where addIndex x = state (\k -> ((k, x), k+1))
scanMap :: (Traversable t) => (a -> a) -> t a -> [t a]
scanMap f t =
let (ti, n) = indexed (fmap (\x -> (x, f x)) t)
partial i = fmap (\(k, (x, y)) -> if k < i then y else x) ti
in map partial [1..n]
這裏,indexed
工作在狀態單子到一個遞增索引添加到可橫越對象的元件(以及得到的長度「免費」,這意味着什麼):
> indexed ['a','b','c']
([(0,'a'),(1,'b'),(2,'c')],3)
,並再次,作爲本所指出的,它也可以使用mapAccumL
寫:
indexed = swap . mapAccumL (\k x -> (k+1, (k, x))) 0
然後,scanMap
採用可遍歷的對象,將其映射到前/後對的相似結構,使用indexed
來索引它,並應用一系列partial
函數,其中partial i
爲第一個i
元素選擇「afters」,其餘爲「之前」。
> scanMap (*2) [1,2,3]
[[2,2,3],[2,4,3],[2,4,6]]
至於從名單推廣這個別的東西,我無法弄清楚你想與你的第二個簽名到底該怎麼做:
func :: (Traversable t, Applicative f) => (a -> f a) -> t a -> f (t a)
,因爲如果你擅長這個的你得到的列表:
func' :: (Traversable t) => (a -> [a]) -> t a -> [t a]
並且它不完全清楚你想在這裏做什麼。
在一般情況下這是不可能的,因爲應用函數的輸出不必與輸入類型相同。所以中間結果可能像'[「Foo」,2,3]'。你應該重新制定你的要求。 –
@EugeneSh。我認爲這暗示着'(+1)'函數必須是一個endo,否則就不可能了,正如你所解釋的那樣。 – chi
這是「小丑和小丑」的工作。人們可以選擇更靈活和更精確地說明中間狀態。例如[([],(1,2),[2,3]),([2],(2,3),[3]),([2,3],(3,4),[ ])],其中狀態列表中的每個元素都具有相應的輸入元素「in focus」,我們可以看到我們已經在左邊的輸出,我們還沒有訪問的輸入在右邊,並且爲焦點元素配對。對於這樣的結構,映射函數不一定是內核。 – pigworker