Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Yes! Thanks to u/topchetoeuwastaken , I was able to rewrite it so you can now use nil in it. null is only used internally, so you don't have to worry about it.
- It is inspired by Kotlin's when, though it currently only has a sub set of features (I might add the other features later).
- Imagine you want to map a value to another value. If you don't need nil and if the mapping is straight forward, you could use a table. If it gets more complicated, you need a long ifelse chain like so:
- ```Lua
- if x == a then
- return 1
- elseif x == b then
- return 2
- elseif x == c then
- return 3
- else
- return 0
- end
- ```
- This has a couple issues:
- - repeating return, because if is not an expression, so you can't write `return if ...`
- - repeating comparison `x ==`
- A `when` expression can make this more readable:
- ```
- return when(x,
- a, 1,
- b, 2,
- c, 3,
- 0 -- else case
- )
- ```
- I use this to map poker cards to illustrations. What's special here is that most cards of the same rank have the same illustration, but some have different ones, based on rank, which requires the nested `_when`:
- --[[
- returns the drawable to use as
- the given card's illustration.
- ]]
- function gfx.get_illu(c)
- local d = r.drawable
- local cr = card.rank
- local cs = card.suit
- local rank = card.get_rank(c)
- local suit = card.get_suit(c)
- return when(rank,
- -- gestalts --
- nil,
- _when(c,
- card.joker1, d.isa,
- card.joker2, d.ariane),
- -- artifacts --
- cr.ace,
- _when(suit,
- cs.spades, d.shield,
- cs.clubs, d.knife,
- cs.hearts, d.king_in_yellow,
- cs.diamonds, d.plant),
- -- replica --
- 2, d.klbr,
- 3, d.eulr,
- 4, when(suit,
- cs.clubs, d.adlr_knife,
- d.adlr),
- -- special case 5: lstr
- -- has four variants
- 5, _when(suit,
- -- todo draw the other
- -- lstr variants
- cs.spades,d.lstr,--space
- cs.clubs, d.lstr_combat,
- cs.hearts,d.lstr_eaten,
- cs.diamonds, d.lstr),
- 6, d.arar,
- 7, d.star,
- 8, d.stcr,
- 9, d.flkr,
- 10, d.mnhr,
- -- bosses --
- cr.jack, d.corrupted_mnhr,
- cr.queen, d.chimera,
- cr.king, d.corrupted_flkr)
- end
- Here is the implementation, it's currently written in PICO-8 Lua, so if you want to use it somewhere else, you'd have to replace the `add` with a `table.insert`:
- null = {}
- error_thunk = {}
- --[[
- pattern matches with optional
- else fallback. if no else is
- given and nothing matches, it
- crashes.
- When nesting whens, use "_when"
- for all nested whens and only
- "when" for the outer one.
- ]]
- function when(s, ...)
- local result = _when(s,...)
- if(result == error_thunk) then
- -- no match (not exhaustive)
- print("when did not match " ..
- tostring(subject),0,0,8)
- print("result: " ..
- tostring(result))
- print("m:" ..
- tostring(matches))
- for i, v in ipairs(matches) do
- print(tostring(v[1]) ..
- " -> " .. tostring(v[2]))
- end
- local now = t()
- local crashtime = now + 4
- --while(t() < crashtime )do end
- error("when not exhaustive!")
- elseif(result == null) then
- return nil
- end
- return result
- end
- --[[
- Use this for nested whens.
- ]]
- function _when(subject, ...)
- if subject == nil then
- subject = null
- end
- -- also replace nil in args
- local args = {}
- for i=1, select("#", ...) do
- local a = select(i, ...)
- if(a == nil) then
- add(args, null)
- else
- add(args, a)
- end
- end
- local matches =
- partition(args,2)
- local result = nil
- for _,cond in ipairs(matches)do
- if #cond == 1 and
- result == nil then
- result = cond[1]
- elseif subject == cond[1] and
- result == nil then
- result = cond[2]
- end
- end
- -- match found!
- if result != nil then
- return result
- end
- -- no match
- return error_thunk
- end
Add Comment
Please, Sign In to add comment