допустим
data Record = Record
{ field1 :: Text
, field2 :: Int
, ...
, fieldM :: Foo
}
parse1 :: [(Int, Value)] -> Record -> Parser Record
parse1 ((0, f):xs) Record{..} =
parseText f >>= \v -> parseFieldStream xs Record{field1=v, ..}
parse1 ((1, f):xs) Record{..} =
parseInt f >>= \v -> parseFieldStream xs Record{field2=v, ..}
parse1 ... = ...
parse1 [] r = pure r
parse2 :: [(Int, Value)] -> Record -> ParserT (ST s) Record
parse2 s def = do
ref1 <- newSTRef def.field1
ref2 <- newSTRef def.filed2
...
let loop x = \case
((0, v):xs) -> parseText v >>= writeSTRef ref1 >> loop xs
((1, v):xs) -> parseInt v >>= writeSTRef ref2 >> loop xs
...
[] -> Record <$> readSTRef ref1 <*> readSTRef ref2 ...
loop s
Список и Parser не берём в расчёт, и считаем что дешевые.
parse1 в итоге наллоцирует M раз рекорд (что не дорого), и столько же раз скопирует поля, что уже хуже.
А какие подводные у parse2? При желании там хоть IO используй и тогда без ParseT можно исключениями дешево парсер останавливать.