2017-01-29 7 views
9

В Haskell, мы можем использовать эти полезные идиомы, чтобы получить из списка, который индексированные элементов в нем:Haskell: Как сделать слияние фальсификатора/сборки в (zip [0 ..])?

indexify :: (Num i) => [a] -> [(i,a)] 
indexify = zip [0..] 

Однако, по реализации zip в GHC.List as of base-4.9.1.0, это не будет полностью выполнять список слияния, т.е. это не приведет к генерации списка [0 ..], но будет создан список аргументов indexify.

Конечно, есть определение, которое дает возможность обеспечить соответствующее слияние списка:

indexify' :: (Num i) => [a] -> [(i,a)] 
indexify' xs = build $ \c n -> 
       foldr (\x r !i -> (i,x) `c` r (i+1)) (const n) xs 0 

Нужно ли нам import GHC.Prim (build) сделать это? Или существует другая реализация, которая упрощает до indexify'?

+1

Будет ли индексировать = пусть f! I x = (i + 1, (i, x)) в snd. картаAccumL f 0' произведение? Я считаю, что 'mapAccumL' подвержен слиянию. – Alec

+0

@Alec Я собирался превратить ваш комментарий в ответ и принять его, но он не работает. 'mapAccumL' определяется в терминах' traverse = mapM', и он сплавляется в направлении «потребления» (т. е. использует 'foldr'), но он не сливается в направлении« производства »(т. е. не использует' build'). – gksato

+0

Ах. Хорошая точка зрения. Должен был подумать об этом. Еще немного лучше, чем 'zip'. :) – Alec

ответ

5

Это уже существует в пакете ilist, так как indexed. Соответствующий исходных фрагменты код

import GHC.Exts -- exports `build` 

indexed :: [a] -> [(Int, a)] 
indexed xs = go 0# xs 
    where 
    go i (a:as) = (I# i, a) : go (i +# 1#) as 
    go _ _ = [] 
{-# NOINLINE [1] indexed #-} 

indexedFB :: ((Int, a) -> t -> t) -> a -> (Int# -> t) -> Int# -> t 
indexedFB c = \x cont i -> (I# i, x) `c` cont (i +# 1#) 
{-# INLINE [0] indexedFB #-} 

{-# RULES 
"indexed"  [~1] forall xs. indexed xs = build (\c n -> foldr (indexedFB c) (\_ -> n) xs 0#) 
"indexedList" [1] forall xs. foldr (indexedFB (:)) (\_ -> []) xs 0# = indexed xs 
    #-} 

Как вы, вероятно, заметили, правило перезаписи использует довольно много же определение у вас есть, так что, вероятно, это лучший способ сделать это. Также GHC.Exts также экспортирует build, поэтому вам не нужно импортировать GHC.Prim.