lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hi all!

While playing with language, I've came to following implementation of
pattern-matching-for-the-poor in Lua. Any comments?

Example:

match {
    {
      function() return true_if_matched end;
      function(optional_match_results) do_something() end
    };
    {
      function() return true_if_matched_2 end;
      function(optional_match_results) do_something_else() end
    };
    {
      function() return true end;
      function(optional_match_results) default_case() end
    };
  }

To get rid of limitation for unified predicate interface, match
construction assumes predicates work with some upvalues.

While this approach brings considerable syntax and (possibly)
performance overhead, I think it still can be useful in some cases...

With best regards,
Alexander.

--  TODO: This whole thing looks quite performance-hungry.
--  T is table filled with pairs of nullary match-predicates and
result generators,
--  accepting table of return values from match-predicates:
--  t = { {function() ... end, function() ... end} }
--  Matches first valid pattern.
match = function(t)
  local res;
  for _, v in t do
    res = { v[1]() }
    if res[1] then return v[2](res) end
  end

  return assert(false, "No match")()
end

--  Some utility functions
inv = function(v) --  invariant
  return function() return v end
end

default = inv(true);

append_to_iter = function(val, iter)
  local iter_fn
  iter_fn  = function() iter_fn = iter; return val end
  return function()
    return iter_fn();
  end
end

--  Silly example:
my_gfind = function(s, pat)
  local m = string.gfind(s, pat)
  return m(), m
end

--  Some macroses would help greatly to reduce syntax overhead.
classificate = function(str)
  --  Not using inv() for first two cases to delay potentially
performance-hungry evaluation.
  return match {
      {
        function() return my_gfind(str, "%d+") end;
        function(m) return "numbers", append_to_iter(m[1], m[2]) end
      };
      {
        function() return my_gfind(str, "%a+") end;
        function(m) return "letters", append_to_iter(m[1], m[2]) end
      };
      { default; inv(nil) };
    }
end

print_classification = function(str)
  local r = { classificate(str) }

  --  Conventional if would do here :)
  match {
      {
        inv(r[1] ~= nil);
        function()
          print("type: ", r[1], "\nvalues:");
          for val in r[2] do
            print(val);
          end
        end
      };
      { default; function() print("type:", "unclassified") end };
    }
end

print_classification("this matches numbers 1 and 2");
print_classification("this matches words");
print_classification(")($&*#@($*&#$"); -- No match.