{"id":5,"date":"2011-05-16T19:37:26","date_gmt":"2011-05-17T00:37:26","guid":{"rendered":"http:\/\/www.playwithlua.com\/?p=5"},"modified":"2020-05-22T13:13:01","modified_gmt":"2020-05-22T18:13:01","slug":"making-lua-look-like-prolog","status":"publish","type":"post","link":"http:\/\/www.playwithlua.com\/?p=5","title":{"rendered":"Making Lua Look Like Prolog"},"content":{"rendered":"<p>Lua, like most languages, has some object-oriented pieces. But, it doesn&#8217;t have classes and modules and objects: it takes the Scheme approach and gives you the tools you need to <em>build<\/em> the OO paradigm you want to use. In particular, the only data structure it gives you is called a <em>table<\/em> and is essentially a hashtable married to an array (it&#8217;s a hashtable, but it has accelerated access for integer keys, so it&#8217;s efficient to use for either one). Tables can be assigned <em>metatables<\/em> which define special behavior for the table: if you try to access a key that doesn&#8217;t exist, it looks in the metatable for &#8220;__index&#8221; and uses that to find what the value should be.<\/p>\n<p>But if all that was intended was to make it easy to duplicate class-based OO, Lua would just have put in class-based OO, right? Let&#8217;s try something different, that uses this same trick to do something cool. Let&#8217;s make Lua look like Prolog.<\/p>\n<p><!--more-->What we&#8217;re going to do is make it where we can refer to variables without creating them, and expect them to be automatically created for us with the right plumbing. We&#8217;ll do this by making a metatable with an __index method, and sticking it on to a special table called _G, where all the Lua global variables live. So let&#8217;s begin:<\/p>\n<p>Let&#8217;s say that any variable that begins with a capital letter is a noun, so we want to just create an empty table for it (that we can then use to store its relationships to other nouns).<\/p>\n<p>The next part of the __index function checks for any name that starts with &#8220;is_&#8221;. Since we&#8217;re going to create nouns and give them relationships to each other, we&#8217;ll want to query those somehow. So we&#8217;ll say that if (for example) the noun Bob is the boss of the noun Fred, then Fred will have boss = Bob as an entry in his table, and Bob will have boss_of = Fred. If someone asks for a function that starts with &#8220;is_&#8221;, we&#8217;ll make them a function that takes two nouns and returns whether they have that relationship. Here&#8217;s what the function to make those query functions looks like:<\/p>\n\n<div class=\"my_syntax_box\"><div class=\"my_syntax\"><div class=\"code\"><pre class=\"lua\" style=\"font-family:monospace;\"><span style=\"color: #aa9900; font-weight: bold;\">function<\/span> make_predicate<span style=\"color: #66cc66;\">&#40;<\/span>name<span style=\"color: #66cc66;\">&#41;<\/span>\n   <span style=\"color: #aa9900; font-weight: bold;\">local<\/span> rule <span style=\"color: #66cc66;\">=<\/span> name<span style=\"color: #66cc66;\">:<\/span>match<span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #ff6666;\">&quot;^is_(.*)&quot;<\/span><span style=\"color: #66cc66;\">&#41;<\/span>\n   <span style=\"color: #aa9900; font-weight: bold;\">return<\/span> <span style=\"color: #aa9900; font-weight: bold;\">function<\/span><span style=\"color: #66cc66;\">&#40;<\/span>a<span style=\"color: #66cc66;\">,<\/span> b<span style=\"color: #66cc66;\">&#41;<\/span>\n             <span style=\"color: #aa9900; font-weight: bold;\">return<\/span> b<span style=\"color: #66cc66;\">&#91;<\/span>rule<span style=\"color: #66cc66;\">&#93;<\/span> <span style=\"color: #66cc66;\">==<\/span> a\n          <span style=\"color: #aa9900; font-weight: bold;\">end<\/span>\n<span style=\"color: #aa9900; font-weight: bold;\">end<\/span><\/pre><\/div><\/div><\/div>\n\n<p>So now all we need is to make any other missing name be a function that assigns relationships. Here&#8217;s the function to create relationship-makers:<\/p>\n\n<div class=\"my_syntax_box\"><div class=\"my_syntax\"><div class=\"code\"><pre class=\"lua\" style=\"font-family:monospace;\"><span style=\"color: #aa9900; font-weight: bold;\">function<\/span> make_rule<span style=\"color: #66cc66;\">&#40;<\/span>name<span style=\"color: #66cc66;\">&#41;<\/span>\n   <span style=\"color: #aa9900; font-weight: bold;\">return<\/span> <span style=\"color: #aa9900; font-weight: bold;\">function<\/span><span style=\"color: #66cc66;\">&#40;<\/span>a<span style=\"color: #66cc66;\">,<\/span> b<span style=\"color: #66cc66;\">&#41;<\/span>\n             a<span style=\"color: #66cc66;\">&#91;<\/span>name <span style=\"color: #66cc66;\">..<\/span> <span style=\"color: #ff6666;\">&quot;_of&quot;<\/span><span style=\"color: #66cc66;\">&#93;<\/span> <span style=\"color: #66cc66;\">=<\/span> b\n             b<span style=\"color: #66cc66;\">&#91;<\/span>name<span style=\"color: #66cc66;\">&#93;<\/span> <span style=\"color: #66cc66;\">=<\/span> a\n          <span style=\"color: #aa9900; font-weight: bold;\">end<\/span>\n<span style=\"color: #aa9900; font-weight: bold;\">end<\/span><\/pre><\/div><\/div><\/div>\n\n<p>All that&#8217;s left is making the __index function that catches references to variables that don&#8217;t exist, and putting it in _G&#8217;s metatable:<\/p>\n\n<div class=\"my_syntax_box\"><div class=\"my_syntax\"><div class=\"code\"><pre class=\"lua\" style=\"font-family:monospace;\"><span style=\"color: #0000aa;\">setmetatable<\/span><span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #0000aa;\">_G<\/span><span style=\"color: #66cc66;\">,<\/span><span style=\"color: #66cc66;\">&#123;<\/span> __index <span style=\"color: #66cc66;\">=<\/span>\n                  <span style=\"color: #aa9900; font-weight: bold;\">function<\/span><span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #0000aa;\">globals<\/span><span style=\"color: #66cc66;\">,<\/span> name<span style=\"color: #66cc66;\">&#41;<\/span>\n                     <span style=\"color: #aa9900; font-weight: bold;\">if<\/span> name<span style=\"color: #66cc66;\">:<\/span>match<span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #ff6666;\">&quot;^[A-Z]&quot;<\/span><span style=\"color: #66cc66;\">&#41;<\/span> <span style=\"color: #aa9900; font-weight: bold;\">then<\/span> <span style=\"color: #808080; font-style: italic;\">-- entity<\/span>\n                        <span style=\"color: #0000aa;\">rawset<\/span><span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #0000aa;\">globals<\/span><span style=\"color: #66cc66;\">,<\/span> name<span style=\"color: #66cc66;\">,<\/span> <span style=\"color: #66cc66;\">&#123;<\/span> <span style=\"color: #66cc66;\">&#125;<\/span><span style=\"color: #66cc66;\">&#41;<\/span>\n                     <span style=\"color: #aa9900; font-weight: bold;\">elseif<\/span> name<span style=\"color: #66cc66;\">:<\/span>match<span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #ff6666;\">&quot;^is_&quot;<\/span><span style=\"color: #66cc66;\">&#41;<\/span> <span style=\"color: #aa9900; font-weight: bold;\">then<\/span> <span style=\"color: #808080; font-style: italic;\">-- predicate<\/span>\n                        <span style=\"color: #aa9900; font-weight: bold;\">local<\/span> pred <span style=\"color: #66cc66;\">=<\/span> make_predicate<span style=\"color: #66cc66;\">&#40;<\/span>name<span style=\"color: #66cc66;\">&#41;<\/span>\n                        <span style=\"color: #0000aa;\">rawset<\/span><span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #0000aa;\">globals<\/span><span style=\"color: #66cc66;\">,<\/span> name<span style=\"color: #66cc66;\">,<\/span> pred<span style=\"color: #66cc66;\">&#41;<\/span>\n                     <span style=\"color: #aa9900; font-weight: bold;\">else<\/span> <span style=\"color: #808080; font-style: italic;\">-- rule<\/span>\n                        <span style=\"color: #aa9900; font-weight: bold;\">local<\/span> rule <span style=\"color: #66cc66;\">=<\/span> make_rule<span style=\"color: #66cc66;\">&#40;<\/span>name<span style=\"color: #66cc66;\">&#41;<\/span>\n                        <span style=\"color: #0000aa;\">rawset<\/span><span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #0000aa;\">globals<\/span><span style=\"color: #66cc66;\">,<\/span> name<span style=\"color: #66cc66;\">,<\/span> rule<span style=\"color: #66cc66;\">&#41;<\/span>\n                     <span style=\"color: #aa9900; font-weight: bold;\">end<\/span>\n                     <span style=\"color: #aa9900; font-weight: bold;\">return<\/span> <span style=\"color: #0000aa;\">rawget<\/span><span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #0000aa;\">globals<\/span><span style=\"color: #66cc66;\">,<\/span> name<span style=\"color: #66cc66;\">&#41;<\/span>\n                  <span style=\"color: #aa9900; font-weight: bold;\">end<\/span> <span style=\"color: #66cc66;\">&#125;<\/span><span style=\"color: #66cc66;\">&#41;<\/span><\/pre><\/div><\/div><\/div>\n\n<p>So now we&#8217;ve got a system where we can specify facts and then ask questions about them. It doesn&#8217;t have any kind of logical analyzer like an actual Prolog implementation would, but if you wrote one, this could be an excellent way to use Lua to feed facts to it. Let&#8217;s toss in a few now:<\/p>\n\n<div class=\"my_syntax_box\"><div class=\"my_syntax\"><div class=\"code\"><pre class=\"lua\" style=\"font-family:monospace;\">father<span style=\"color: #66cc66;\">&#40;<\/span>Vader<span style=\"color: #66cc66;\">,<\/span> Luke<span style=\"color: #66cc66;\">&#41;<\/span>\nfather<span style=\"color: #66cc66;\">&#40;<\/span>Vader<span style=\"color: #66cc66;\">,<\/span> Leia<span style=\"color: #66cc66;\">&#41;<\/span>\n&nbsp;\nfriend<span style=\"color: #66cc66;\">&#40;<\/span>Vader<span style=\"color: #66cc66;\">,<\/span> Emperor<span style=\"color: #66cc66;\">&#41;<\/span>\nfriend<span style=\"color: #66cc66;\">&#40;<\/span>Emperor<span style=\"color: #66cc66;\">,<\/span> Vader<span style=\"color: #66cc66;\">&#41;<\/span>\nfriend<span style=\"color: #66cc66;\">&#40;<\/span>Han<span style=\"color: #66cc66;\">,<\/span> Luke<span style=\"color: #66cc66;\">&#41;<\/span>\nfriend<span style=\"color: #66cc66;\">&#40;<\/span>Luke<span style=\"color: #66cc66;\">,<\/span> Han<span style=\"color: #66cc66;\">&#41;<\/span>\n&nbsp;\nbrother<span style=\"color: #66cc66;\">&#40;<\/span>Luke<span style=\"color: #66cc66;\">,<\/span> Leia<span style=\"color: #66cc66;\">&#41;<\/span>\nsister<span style=\"color: #66cc66;\">&#40;<\/span>Leia<span style=\"color: #66cc66;\">,<\/span> Luke<span style=\"color: #66cc66;\">&#41;<\/span><\/pre><\/div><\/div><\/div>\n\n<p>And then a few asserts, to verify everything works:<\/p>\n\n<div class=\"my_syntax_box\"><div class=\"my_syntax\"><div class=\"code\"><pre class=\"lua\" style=\"font-family:monospace;\"><span style=\"color: #0000aa;\">assert<\/span><span style=\"color: #66cc66;\">&#40;<\/span>is_father<span style=\"color: #66cc66;\">&#40;<\/span>Vader<span style=\"color: #66cc66;\">,<\/span> Luke<span style=\"color: #66cc66;\">&#41;<\/span><span style=\"color: #66cc66;\">&#41;<\/span>\n<span style=\"color: #0000aa;\">assert<\/span><span style=\"color: #66cc66;\">&#40;<\/span>is_sister<span style=\"color: #66cc66;\">&#40;<\/span>Leia<span style=\"color: #66cc66;\">,<\/span> Luke<span style=\"color: #66cc66;\">&#41;<\/span><span style=\"color: #66cc66;\">&#41;<\/span>\n<span style=\"color: #0000aa;\">assert<\/span><span style=\"color: #66cc66;\">&#40;<\/span>is_friend<span style=\"color: #66cc66;\">&#40;<\/span>Han<span style=\"color: #66cc66;\">,<\/span> Luke<span style=\"color: #66cc66;\">&#41;<\/span><span style=\"color: #66cc66;\">&#41;<\/span>\n<span style=\"color: #0000aa;\">assert<\/span><span style=\"color: #66cc66;\">&#40;<\/span>is_friend<span style=\"color: #66cc66;\">&#40;<\/span>Luke<span style=\"color: #66cc66;\">,<\/span> Han<span style=\"color: #66cc66;\">&#41;<\/span><span style=\"color: #66cc66;\">&#41;<\/span>\n&nbsp;\n<span style=\"color: #0000aa;\">assert<\/span><span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #aa9900; font-weight: bold;\">not<\/span> is_friend<span style=\"color: #66cc66;\">&#40;<\/span>Vader<span style=\"color: #66cc66;\">,<\/span> Luke<span style=\"color: #66cc66;\">&#41;<\/span><span style=\"color: #66cc66;\">&#41;<\/span>\n<span style=\"color: #0000aa;\">assert<\/span><span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #aa9900; font-weight: bold;\">not<\/span> is_friend<span style=\"color: #66cc66;\">&#40;<\/span>Han<span style=\"color: #66cc66;\">,<\/span> Jabba<span style=\"color: #66cc66;\">&#41;<\/span><span style=\"color: #66cc66;\">&#41;<\/span><\/pre><\/div><\/div><\/div>\n\n<p>And we&#8217;re done. You can see all this code in one place on Github <a onclick=\"javascript:pageTracker._trackPageview('\/outgoing\/gist.github.com\/897798');\"  href=\"https:\/\/gist.github.com\/897798\">here<\/a>.<\/p>\n<p>Lua and its metatables are really cool, and using them only to fake a boring language feature like classes is just a lack of imagination. It&#8217;s a really sharp tool, make cool things with it!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Lua, like most languages, has some object-oriented pieces. But, it doesn&#8217;t have classes and modules and objects: it takes the Scheme approach and gives you the tools you need to build the OO paradigm you want to use. In particular, the only data structure it gives you is called a table and is essentially a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=\/wp\/v2\/posts\/5"}],"collection":[{"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=5"}],"version-history":[{"count":0,"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=\/wp\/v2\/posts\/5\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}