Guest User

Lua when v2

a guest
Sep 21st, 2025
22
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 3.71 KB | None | 0 0
  1. 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.
  2. It is inspired by Kotlin's when, though it currently only has a sub set of features (I might add the other features later).
  3. 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:
  4.  
  5. ```Lua
  6. if x == a then
  7. return 1
  8. elseif x == b then
  9. return 2
  10. elseif x == c then
  11. return 3
  12. else
  13. return 0
  14. end
  15. ```
  16.  
  17. This has a couple issues:
  18. - repeating return, because if is not an expression, so you can't write `return if ...`
  19. - repeating comparison `x ==`
  20. A `when` expression can make this more readable:
  21.  
  22. ```
  23. return when(x,
  24.  a, 1,
  25.  b, 2,
  26.  c, 3,
  27.  0   -- else case
  28. )
  29. ```
  30.  
  31. 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`:
  32.  
  33. --[[
  34. returns the drawable to use as
  35. the given card's illustration.
  36. ]]
  37. function gfx.get_illu(c)
  38.  local d = r.drawable
  39.  local cr = card.rank
  40.  local cs = card.suit
  41.  local rank = card.get_rank(c)
  42.  local suit = card.get_suit(c)
  43.  return when(rank,
  44.  
  45.   -- gestalts --
  46.   nil,
  47.    _when(c,
  48.     card.joker1, d.isa,
  49.     card.joker2, d.ariane),
  50.  
  51.   -- artifacts --
  52.   cr.ace,
  53.    _when(suit,
  54.     cs.spades, d.shield,
  55.     cs.clubs,  d.knife,
  56.     cs.hearts, d.king_in_yellow,
  57.     cs.diamonds, d.plant),
  58.  
  59.   -- replica --
  60.    2, d.klbr,
  61.    3, d.eulr,
  62.    4, when(suit,
  63.        cs.clubs, d.adlr_knife,
  64.        d.adlr),
  65.    -- special case 5: lstr
  66.    -- has four variants
  67.    5, _when(suit,
  68.        -- todo draw the other
  69.        -- lstr variants
  70.        cs.spades,d.lstr,--space
  71.        cs.clubs, d.lstr_combat,
  72.        cs.hearts,d.lstr_eaten,
  73.        cs.diamonds, d.lstr),
  74.    6, d.arar,
  75.    7, d.star,
  76.    8, d.stcr,
  77.    9, d.flkr,
  78.   10, d.mnhr,
  79.  
  80.   -- bosses --
  81.   cr.jack,  d.corrupted_mnhr,
  82.   cr.queen, d.chimera,
  83.   cr.king,  d.corrupted_flkr)
  84. end
  85.  
  86. 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`:
  87. null = {}
  88. error_thunk = {}
  89.  
  90. --[[
  91. pattern matches with optional
  92. else fallback. if no else is
  93. given and nothing matches, it
  94. crashes.
  95.  
  96. When nesting whens, use "_when"
  97. for all nested whens and only
  98. "when" for the outer one.
  99. ]]
  100. function when(s, ...)
  101.  local result = _when(s,...)
  102.  if(result == error_thunk) then
  103.    -- no match (not exhaustive)
  104.   print("when did not match " ..
  105.     tostring(subject),0,0,8)
  106.   print("result: " ..
  107.    tostring(result))
  108.   print("m:" ..
  109.    tostring(matches))
  110.   for i, v in ipairs(matches) do
  111.     print(tostring(v[1]) ..
  112.     " -> " .. tostring(v[2]))
  113.   end
  114.   local now = t()
  115.   local crashtime = now + 4
  116. --while(t() < crashtime )do end
  117.   error("when not exhaustive!")
  118.  elseif(result == null) then
  119.   return nil
  120.  end
  121.  return result
  122. end
  123.  
  124. --[[
  125. Use this for nested whens.
  126. ]]
  127. function _when(subject, ...)
  128.  if subject == nil then
  129.   subject = null
  130.  end
  131.  -- also replace nil in args
  132.  local args = {}
  133.  for i=1, select("#", ...) do
  134.   local a = select(i, ...)
  135.   if(a == nil) then
  136.    add(args, null)
  137.   else
  138.    add(args, a)
  139.   end
  140.  end
  141.  
  142.  local matches =
  143.   partition(args,2)
  144.  
  145.  local result = nil
  146.  for _,cond in ipairs(matches)do
  147.   if #cond == 1 and
  148.    result == nil then
  149.    result = cond[1]
  150.   elseif subject == cond[1] and
  151.    result == nil then
  152.    result = cond[2]
  153.   end
  154.  end
  155.  
  156.  -- match found!
  157.  if result != nil then
  158.   return result
  159.  end
  160.  
  161.  -- no match
  162.  return error_thunk
  163. end
Add Comment
Please, Sign In to add comment