on master help sign in
Shuffle the optimized AST to make code gen easier

For example, each case expression saves a temporary variable just in case. That means we do all variable name generation in the optimize phase, so the generate phase can be pure function from Elm to JS AST.

commit8a89c868b2d6a4b916e60c7307d2d84e3a26c1f2 authorEvan Czaplicki <evancz@users.noreply.github.com> dateTue 5 Dec 2017, 14:34 (9 years ago) parent022925a
6 files changed+116−131
src/AST/Optimized.hs+25−27 src/Optimize/Case.hs+11−25 src/Optimize/DecisionTree.hs+20−19 src/Optimize/Expression.hs+40−31 src/Optimize/Module.hs+6−15 src/Optimize/Port.hs+14−14
src/AST/Optimized.hs+25−27
@@ -39,17 +39,16 @@ data Expr
3939 | VarLocal N.Name
4040 | VarGlobal Global
4141 | VarCycle ModuleName.Canonical N.Name
42− | VarDebug N.Name ModuleName.Canonical R.Region (Maybe Expr)
42+ | VarDebug N.Name ModuleName.Canonical R.Region (Maybe N.Name)
4343 | VarKernel N.Name N.Name
4444 | List [Expr]
4545 | Function [N.Name] Expr
4646 | Call Expr [Expr]
47− | TailCall N.Name [N.Name] [Expr]
47+ | TailCall N.Name [(N.Name, Expr)]
4848 | If [(Expr, Expr)] Expr
4949 | Let Def Expr
50− | Case N.Name (Decider Choice) [(Int, Expr)]
51− | Ctor N.Name [Expr]
52− | CtorAccess Expr Index.ZeroBased
50+ | Case N.Name N.Name (Decider Choice) [(Int, Expr)]
51+ | Index Expr Int
5352 | Accessor N.Name
5453 | Access Expr N.Name
5554 | Update Expr (Map.Map N.Name Expr)
@@ -116,6 +115,7 @@ data Main
116115data Node
117116 = Define Expr (Set.Set N.Name) (Set.Set Global)
118117 | DefineTailFunc [N.Name] Expr (Set.Set N.Name) (Set.Set Global)
118+ | Ctor N.Name Index.ZeroBased Int
119119 | Link Global
120120 | Cycle [(N.Name, Expr)] (Set.Set N.Name) (Set.Set Global)
121121 | PortIncoming Expr (Set.Set N.Name) (Set.Set Global)
@@ -150,19 +150,18 @@ instance Binary Expr where
150150 List a -> putWord8 9 >> put a
151151 Function a b -> putWord8 10 >> put a >> put b
152152 Call a b -> putWord8 11 >> put a >> put b
153− TailCall a b c -> putWord8 12 >> put a >> put b >> put c
153+ TailCall a b -> putWord8 12 >> put a >> put b
154154 If a b -> putWord8 13 >> put a >> put b
155155 Let a b -> putWord8 14 >> put a >> put b
156− Case a b c -> putWord8 15 >> put a >> put b >> put c
157− Ctor a b -> putWord8 16 >> put a >> put b
158− CtorAccess a b -> putWord8 17 >> put a >> put b
159− Accessor a -> putWord8 18 >> put a
160− Access a b -> putWord8 19 >> put a >> put b
161− Update a b -> putWord8 20 >> put a >> put b
162− Record a -> putWord8 21 >> put a
163− Unit -> putWord8 22
164− Tuple a b c -> putWord8 23 >> put a >> put b >> put c
165− Shader a -> putWord8 24 >> put a
156+ Case a b c d -> putWord8 15 >> put a >> put b >> put c >> put d
157+ Index a b -> putWord8 16 >> put a >> put b
158+ Accessor a -> putWord8 17 >> put a
159+ Access a b -> putWord8 18 >> put a >> put b
160+ Update a b -> putWord8 19 >> put a >> put b
161+ Record a -> putWord8 20 >> put a
162+ Unit -> putWord8 21
163+ Tuple a b c -> putWord8 22 >> put a >> put b >> put c
164+ Shader a -> putWord8 23 >> put a
166165
167166 get =
168167 do word <- getWord8
@@ -179,19 +178,18 @@ instance Binary Expr where
179178 9 -> liftM List get
180179 10 -> liftM2 Function get get
181180 11 -> liftM2 Call get get
182− 12 -> liftM3 TailCall get get get
181+ 12 -> liftM2 TailCall get get
183182 13 -> liftM2 If get get
184183 14 -> liftM2 Let get get
185− 15 -> liftM3 Case get get get
186− 16 -> liftM2 Ctor get get
187− 17 -> liftM2 CtorAccess get get
188− 18 -> liftM Accessor get
189− 19 -> liftM2 Access get get
190− 20 -> liftM2 Update get get
191− 21 -> liftM Record get
192− 22 -> pure Unit
193− 23 -> liftM3 Tuple get get get
194− 24 -> liftM Shader get
184+ 15 -> liftM4 Case get get get get
185+ 16 -> liftM2 Index get get
186+ 17 -> liftM Accessor get
187+ 18 -> liftM2 Access get get
188+ 19 -> liftM2 Update get get
189+ 20 -> liftM Record get
190+ 21 -> pure Unit
191+ 22 -> liftM3 Tuple get get get
192+ 23 -> liftM Shader get
195193 _ -> error "problem getting Opt.Expr binary"
196194
197195
src/Optimize/Case.hs+11−25
@@ -20,13 +20,21 @@ import qualified Optimize.DecisionTree as DT
2020-- OPTIMIZE A CASE EXPRESSION
2121
2222
23−optimize :: N.Name -> [(Can.Pattern, Opt.Expr)] -> Opt.Expr
24−optimize exprName optBranches =
23+optimize :: N.Name -> N.Name -> [(Can.Pattern, Opt.Expr)] -> Opt.Expr
24+optimize temp root optBranches =
2525 let
2626 (patterns, indexedBranches) =
2727 unzip (zipWith indexify [0..] optBranches)
28+
29+ decider = treeToDecider (DT.compile patterns)
30+ targetCounts = countTargets decider
31+
32+ (choices, maybeJumps) =
33+ unzip (map (createChoices targetCounts) indexedBranches)
2834 in
29− treeToExpr exprName (DT.compile patterns) indexedBranches
35+ Opt.Case temp root
36+ (insertChoices (Map.fromList choices) decider)
37+ (Maybe.catMaybes maybeJumps)
3038
3139
3240indexify :: Int -> (a,b) -> ((a,Int), (Int,b))
@@ -37,28 +45,6 @@ indexify index (pattern, branch) =
3745
3846
3947
40−-- CONVERT A TREE TO AN EXPRESSION
41−
42−
43−treeToExpr :: N.Name -> DT.DecisionTree -> [(Int, Opt.Expr)] -> Opt.Expr
44−treeToExpr name decisionTree allJumps =
45− let
46− decider =
47− treeToDecider decisionTree
48−
49− targetCounts =
50− countTargets decider
51−
52− (choices, maybeJumps) =
53− unzip (map (createChoices targetCounts) allJumps)
54− in
55− Opt.Case
56− name
57− (insertChoices (Map.fromList choices) decider)
58− (Maybe.catMaybes maybeJumps)
59−
60−
61−
6248-- TREE TO DECIDER
6349--
6450-- Decision trees may have some redundancies, so we convert them to a Decider
src/Optimize/DecisionTree.hs+20−19
@@ -21,7 +21,7 @@ as SML/NJ to get nice trees.
2121-}
2222
2323import Control.Arrow (second)
24−import Control.Monad (liftM, liftM2)
24+import Control.Monad (liftM, liftM2, liftM3)
2525import Data.Binary
2626import qualified Data.List as List
2727import qualified Data.Maybe as Maybe
@@ -29,6 +29,7 @@ import qualified Data.Set as Set
2929import Data.Text (Text)
3030
3131import qualified AST.Canonical as Can
32+import qualified Data.Index as Index
3233import qualified Elm.Name as N
3334import qualified Reporting.Annotation as A
3435
@@ -70,7 +71,7 @@ data DecisionTree
7071
7172
7273data Test
73− = IsCtor Int N.Name
74+ = IsCtor Int N.Name Index.ZeroBased
7475 | IsInt Int
7576 | IsChr Text
7677 | IsStr Text
@@ -162,7 +163,7 @@ toDecisionTree rawBranches =
162163isComplete :: [Test] -> Bool
163164isComplete tests =
164165 case head tests of
165− IsCtor alts _ ->
166+ IsCtor alts _ _ ->
166167 alts == length tests
167168
168169 _ ->
@@ -207,7 +208,7 @@ flatten pathPattern@(path, A.At region pattern) =
207208 Can.PTuple a b (Just c) ->
208209 concatMap flatten (subPositions path [a,b,c])
209210
210− Can.PCtor _ _ _ (Can.CtorAlts numAlts _) _ args ->
211+ Can.PCtor _ _ _ (Can.CtorAlts numAlts _) _ _ args ->
211212 if numAlts == 1 then
212213 concatMap flatten (subPositions path (map dearg args))
213214 else
@@ -304,8 +305,8 @@ testAtPath selectedPath (Branch _ pathPatterns) =
304305
305306 Just (A.At _ pattern) ->
306307 case pattern of
307− Can.PCtor _ _ _ (Can.CtorAlts numAlts _) name _ ->
308− Just (IsCtor numAlts name)
308+ Can.PCtor _ _ _ (Can.CtorAlts numAlts _) name index _ ->
309+ Just (IsCtor numAlts name index)
309310
310311 Can.PInt int ->
311312 Just (IsInt int)
@@ -346,12 +347,12 @@ testAtPath selectedPath (Branch _ pathPatterns) =
346347
347348{-# NOINLINE nilTest #-}
348349nilTest :: Test
349−nilTest = IsCtor 2 "[]"
350+nilTest = IsCtor 2 "[]" (Index.unsafe (-1))
350351
351352
352353{-# NOINLINE consTest #-}
353354consTest :: Test
354−consTest = IsCtor 2 "::"
355+consTest = IsCtor 2 "::" (Index.unsafe (-2))
355356
356357
357358
@@ -370,27 +371,27 @@ toRelevantBranch test path branch@(Branch goal pathPatterns) =
370371 case extract path pathPatterns of
371372 Just (start, A.At region pattern, end) ->
372373 case pattern of
373− Can.PCtor _ _ _ (Can.CtorAlts numAlts _) name args ->
374− if test == IsCtor numAlts name then
374+ Can.PCtor _ _ _ (Can.CtorAlts numAlts _) name index args ->
375+ if test == IsCtor numAlts name index then
375376 Just (Branch goal (start ++ subPositions path (map dearg args) ++ end))
376377 else
377378 Nothing
378379
379380 Can.PList [] ->
380− if test == IsCtor 2 "[]" then
381+ if test == nilTest then
381382 Just (Branch goal (start ++ end))
382383 else
383384 Nothing
384385
385386 Can.PList (hd:tl) ->
386− if test == IsCtor 2 "::" then
387+ if test == consTest then
387388 let tl' = A.At region (Can.PList tl) in
388389 Just (Branch goal (start ++ subPositions path [ hd, tl' ] ++ end))
389390 else
390391 Nothing
391392
392393 Can.PCons hd tl ->
393− if test == IsCtor 2 "::" then
394+ if test == consTest then
394395 Just (Branch goal (start ++ subPositions path [hd,tl] ++ end))
395396 else
396397 Nothing
@@ -471,7 +472,7 @@ needsTests (A.At _ pattern) =
471472 Can.PRecord _ ->
472473 False
473474
474− Can.PCtor _ _ _ _ _ _ ->
475+ Can.PCtor _ _ _ _ _ _ _ ->
475476 True
476477
477478 Can.PList _ ->
@@ -573,15 +574,15 @@ smallBranchingFactor branches path =
573574instance Binary Test where
574575 put test =
575576 case test of
576− IsCtor a b -> putWord8 0 >> put a >> put b
577− IsChr a -> putWord8 1 >> put a
578− IsStr a -> putWord8 2 >> put a
579− IsInt a -> putWord8 3 >> put a
577+ IsCtor a b c -> putWord8 0 >> put a >> put b >> put c
578+ IsChr a -> putWord8 1 >> put a
579+ IsStr a -> putWord8 2 >> put a
580+ IsInt a -> putWord8 3 >> put a
580581
581582 get =
582583 do word <- getWord8
583584 case word of
584− 0 -> liftM2 IsCtor get get
585+ 0 -> liftM3 IsCtor get get get
585586 1 -> liftM IsChr get
586587 2 -> liftM IsStr get
587588 3 -> liftM IsInt get
src/Optimize/Expression.hs+40−31
@@ -130,14 +130,14 @@ optimize cycle (A.At region expression) =
130130 obranch <- optimize cycle branch
131131 pure (pattern, foldr Opt.Let obranch defs)
132132 in
133− do oexpr <- optimize cycle expr
133+ do temp <- Names.generate
134+ oexpr <- optimize cycle expr
134135 case oexpr of
135136 Opt.VarLocal root ->
136− Case.optimize root <$> traverse (optimizeBranch root) branches
137+ Case.optimize temp root <$> traverse (optimizeBranch root) branches
137138
138139 _ ->
139− do root <- Names.generate
140− Case.optimize root <$> traverse (optimizeBranch root) branches
140+ Case.optimize temp temp <$> traverse (optimizeBranch temp) branches
141141
142142 Can.Accessor field ->
143143 Names.registerField field (Opt.Accessor field)
@@ -246,13 +246,13 @@ destructHelp root (A.At region pattern) revDefs =
246246 let newRevDefs = Opt.Def name root : revDefs
247247 case maybeC of
248248 Nothing ->
249− destructHelp (Opt.CtorAccess tuple Index.second) b =<<
250− destructHelp (Opt.CtorAccess tuple Index.first) a newRevDefs
249+ destructHelp (Opt.Index tuple 1) b =<<
250+ destructHelp (Opt.Index tuple 0) a newRevDefs
251251
252252 Just c ->
253− destructHelp (Opt.CtorAccess tuple Index.third) c =<<
254− destructHelp (Opt.CtorAccess tuple Index.second) b =<<
255− destructHelp (Opt.CtorAccess tuple Index.first) a newRevDefs
253+ destructHelp (Opt.Index tuple 2) c =<<
254+ destructHelp (Opt.Index tuple 1) b =<<
255+ destructHelp (Opt.Index tuple 0) a newRevDefs
256256
257257 Can.PList [] ->
258258 pure revDefs
@@ -272,7 +272,7 @@ destructHelp root (A.At region pattern) revDefs =
272272 Can.PInt _ ->
273273 pure revDefs
274274
275− Can.PCtor _ _ _ _ _ args ->
275+ Can.PCtor _ _ _ _ _ _ args ->
276276 do name <- Names.generate
277277 foldM
278278 (destructCtorArg (Opt.VarLocal name))
@@ -284,13 +284,13 @@ destructCons :: Opt.Expr -> Can.Pattern -> Can.Pattern -> [Opt.Def] -> Names.Tra
284284destructCons root hd tl revDefs =
285285 do name <- Names.generate
286286 let list = Opt.VarLocal name
287− destructHelp (Opt.CtorAccess list Index.first) hd =<<
288− destructHelp (Opt.CtorAccess list Index.second) tl (Opt.Def name root : revDefs)
287+ destructHelp (Opt.Index list 0) hd =<<
288+ destructHelp (Opt.Index list 1) tl (Opt.Def name root : revDefs)
289289
290290
291291destructCtorArg :: Opt.Expr -> [Opt.Def] -> Can.PatternCtorArg -> Names.Tracker [Opt.Def]
292292destructCtorArg root revDefs (Can.PatternCtorArg index _ arg) =
293− destructHelp (Opt.CtorAccess root index) arg revDefs
293+ destructHelp (Opt.Index root (Index.toZeroBased index)) arg revDefs
294294
295295
296296
@@ -312,37 +312,46 @@ optimizePotentialTailCall cycle def =
312312
313313
314314optimizeTail :: Cycle -> N.Name -> [N.Name] -> Can.Expr -> Names.Tracker Opt.Expr
315−optimizeTail cycle name argNames locExpr@(A.At _ expression) =
315+optimizeTail cycle rootName argNames locExpr@(A.At _ expression) =
316316 case expression of
317− Can.Call (A.At _ (Can.VarTopLevel _ funcName)) args ->
318− if funcName == name && length args == length argNames then
319− Opt.TailCall name argNames <$> traverse (optimize cycle) args
320− else
321− optimize cycle locExpr
317+ Can.Call func@(A.At _ (Can.VarTopLevel _ name)) args ->
318+ do oargs <- traverse (optimize cycle) args
319+ if name == rootName
320+ then
321+ case Index.indexedZipWith (\_ a b -> (a,b)) argNames oargs of
322+ Index.LengthMatch pairs ->
323+ pure $ Opt.TailCall name pairs
324+
325+ Index.LengthMismatch _ _ ->
326+ do ofunc <- optimize cycle func
327+ pure $ Opt.Call ofunc oargs
328+ else
329+ do ofunc <- optimize cycle func
330+ pure $ Opt.Call ofunc oargs
322331
323332 Can.If branches finally ->
324333 let
325334 optimizeBranch (condition, branch) =
326335 (,)
327336 <$> optimize cycle condition
328− <*> optimizeTail cycle name argNames branch
337+ <*> optimizeTail cycle rootName argNames branch
329338 in
330339 Opt.If
331340 <$> traverse optimizeBranch branches
332− <*> optimizeTail cycle name argNames finally
341+ <*> optimizeTail cycle rootName argNames finally
333342
334343 Can.Let def body ->
335− optimizeDef cycle def =<< optimizeTail cycle name argNames body
344+ optimizeDef cycle def =<< optimizeTail cycle rootName argNames body
336345
337346 Can.LetRec defs body ->
338347 case defs of
339348 [def] ->
340349 Opt.Let
341350 <$> optimizePotentialTailCall cycle def
342− <*> optimizeTail cycle name argNames body
351+ <*> optimizeTail cycle rootName argNames body
343352
344353 _ ->
345− do obody <- optimizeTail cycle name argNames body
354+ do obody <- optimizeTail cycle rootName argNames body
346355 foldM (\bod def -> optimizeDef cycle def bod) obody defs
347356
348357 Can.LetDestruct pattern expr body ->
@@ -356,17 +365,17 @@ optimizeTail cycle name argNames locExpr@(A.At _ expression) =
356365 let
357366 optimizeBranch root (Can.CaseBranch pattern branch) =
358367 do defs <- destructHelp (Opt.VarLocal root) pattern []
359− obranch <- optimizeTail cycle name argNames branch
368+ obranch <- optimizeTail cycle rootName argNames branch
360369 pure (pattern, foldr Opt.Let obranch defs)
361370 in
362− do oexpr <- optimize cycle expr
371+ do temp <- Names.generate
372+ oexpr <- optimize cycle expr
363373 case oexpr of
364374 Opt.VarLocal root ->
365− Case.optimize root <$> traverse (optimizeBranch root) branches
375+ Case.optimize temp root <$> traverse (optimizeBranch root) branches
366376
367377 _ ->
368− do root <- Names.generate
369− Case.optimize root <$> traverse (optimizeBranch root) branches
378+ Case.optimize temp temp <$> traverse (optimizeBranch temp) branches
370379
371380 _ ->
372381 optimize cycle locExpr
@@ -387,7 +396,7 @@ toTailDef name argNames defss body =
387396hasTailCall :: Opt.Expr -> Bool
388397hasTailCall expression =
389398 case expression of
390− Opt.TailCall _ _ _ ->
399+ Opt.TailCall _ _ ->
391400 True
392401
393402 Opt.If branches finally ->
@@ -396,7 +405,7 @@ hasTailCall expression =
396405 Opt.Let _ body ->
397406 hasTailCall body
398407
399− Opt.Case _ _ branches ->
408+ Opt.Case _ _ _ branches ->
400409 any (hasTailCall . snd) branches
401410
402411 _ ->
src/Optimize/Module.hs+6−15
@@ -15,6 +15,7 @@ import qualified Data.Set as Set
1515import qualified AST.Canonical as Can
1616import qualified AST.Optimized as Opt
1717import qualified AST.Module.Name as ModuleName
18+import qualified Data.Index as Index
1819import qualified Elm.Name as N
1920import qualified Optimize.Expression as Expr
2021import qualified Optimize.Names as Names
@@ -58,23 +59,13 @@ addUnions home unions (Graph fields nodes) =
5859
5960addUnion :: ModuleName.Canonical -> Can.Union -> Nodes -> Nodes
6061addUnion home (Can.Union _ ctors) nodes =
61− foldr (addCtor home) nodes ctors
62+ Map.union nodes $
63+ Map.fromList (Index.indexedMap (ctorToNode home) ctors)
6264
6365
64−addCtor :: ModuleName.Canonical -> (N.Name, [t]) -> Nodes -> Nodes
65−addCtor home (ctor, args) nodes =
66− let
67− argNames =
68− map N.localFromInt [ 1 .. length args ]
69−
70− function =
71− Opt.Function argNames $
72− Opt.Ctor ctor (map Opt.VarLocal argNames)
73−
74− node =
75− Opt.Define function Set.empty Set.empty
76− in
77− Map.insert (Opt.Global home ctor) node nodes
66+ctorToNode :: ModuleName.Canonical -> Index.ZeroBased -> (N.Name, [t]) -> (Opt.Global, Opt.Node)
67+ctorToNode home index (name, args) =
68+ ( Opt.Global home name, Opt.Ctor name index (length args) )
7869
7970
8071
src/Optimize/Port.hs+14−14
@@ -68,13 +68,13 @@ toEncoder tipe =
6868 let
6969 encodeField (name, fieldType) =
7070 do encoder <- toEncoder fieldType
71− let value = Opt.Call encoder [Opt.Access (Opt.VarLocal "r") name]
71+ let value = Opt.Call encoder [Opt.Access (Opt.VarLocal N.dollar) name]
7272 return $ Opt.Tuple (Opt.Str name) value Nothing
7373 in
7474 do object <- encode "object"
7575 keyValuePairs <- traverse encodeField (Map.toList fields)
7676 Names.registerFieldDict fields $
77− Opt.Function ["r"] (Opt.Call object [Opt.List keyValuePairs])
77+ Opt.Function [N.dollar] (Opt.Call object [Opt.List keyValuePairs])
7878
7979
8080
@@ -86,12 +86,12 @@ encodeMaybe tipe =
8686 do null <- encode "null"
8787 encoder <- toEncoder tipe
8888
89− let test = (DT.Empty, DT.IsCtor 2 "Nothing")
90− let just = Opt.Call encoder [ Opt.CtorAccess (Opt.VarLocal "m") Index.first ]
89+ let test = (DT.Empty, DT.IsCtor 2 "Just" Index.first)
90+ let just = Opt.Call encoder [ Opt.Index (Opt.VarLocal N.dollar) 0 ]
9191 let leaf expr = Opt.Leaf (Opt.Inline expr)
9292
93− return $ Opt.Function ["m"] $
94− Opt.Case "m" (Opt.Chain [test] (leaf null) (leaf just)) []
93+ return $ Opt.Function [N.dollar] $
94+ Opt.Case N.dollar N.dollar (Opt.Chain [test] (leaf just) (leaf null)) []
9595
9696
9797encodeList :: Can.Type -> Names.Tracker Opt.Expr
@@ -100,8 +100,8 @@ encodeList tipe =
100100 map_ <- Names.registerGlobal ModuleName.list "map"
101101 encoder <- toEncoder tipe
102102 return $
103− Opt.Function ["xs"] $
104− Opt.Call list [ Opt.Call map_ [ encoder, Opt.VarLocal "xs" ] ]
103+ Opt.Function [N.dollar] $
104+ Opt.Call list [ Opt.Call map_ [ encoder, Opt.VarLocal N.dollar ] ]
105105
106106
107107encodeArray :: Can.Type -> Names.Tracker Opt.Expr
@@ -110,8 +110,8 @@ encodeArray tipe =
110110 map_ <- Names.registerGlobal ModuleName.array "map"
111111 encoder <- toEncoder tipe
112112 return $
113− Opt.Function ["xs"] $
114− Opt.Call array [ Opt.Call map_ [ encoder, Opt.VarLocal "xs" ] ]
113+ Opt.Function [N.dollar] $
114+ Opt.Call array [ Opt.Call map_ [ encoder, Opt.VarLocal N.dollar ] ]
115115
116116
117117encodeTuple :: Can.Type -> Can.Type -> Maybe Can.Type -> Names.Tracker Opt.Expr
@@ -119,18 +119,18 @@ encodeTuple a b maybeC =
119119 let
120120 convert index tipe =
121121 do encoder <- toEncoder tipe
122− return $ Opt.Call encoder [ Opt.CtorAccess (Opt.VarLocal "t") index ]
122+ return $ Opt.Call encoder [ Opt.Index (Opt.VarLocal N.dollar) index ]
123123 in
124− Opt.Function ["t"] <$> (
124+ Opt.Function [N.dollar] <$> (
125125 Opt.Call
126126 <$> encode "list"
127127 <*>
128128 case maybeC of
129129 Nothing ->
130− Index.indexedTraverse convert [a,b]
130+ sequence [ convert 0 a, convert 1 b ]
131131
132132 Just c ->
133− Index.indexedTraverse convert [a,b,c]
133+ sequence [ convert 0 a, convert 1 b, convert 2 c ]
134134 )
135135
136136