<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Paul Butcher</title>
  <link href="https://paulbutcher.com/atom.xml" rel="self"/>
  <link href="https://paulbutcher.com"/>
  <updated>2025-01-24T21:27:24+00:00</updated>
  <id>https://paulbutcher.com</id>
  <author>
    <name>Paul Butcher</name>
  </author>
  <entry>
    <id>https://paulbutcher.com/lambda2.html</id>
    <link href="https://paulbutcher.com/lambda2.html"/>
    <title>Quick and Easy Clojure on AWS Lambda Part 2</title>
    <updated>2025-01-24T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<p>This follows on from my <a href='lambda1.html'>previous article</a> which described how to get a simple Clojure Ring application running on AWS Lambda. This article shows how to connect it to a database.</p><p>The accompanying code is <a href='https://github.com/paulbutcher/example-lambda-app2'>here</a>.</p><h2 id="cloudformation">CloudFormation</h2><p>AWS SAM provides direct support for DynamoDB, but not for more traditional databases like PostgreSQL, so that means dropping into CloudFormation. This is, sadly, rather wordy, because we'll need to configure all the neccessary AWS machinery (including setting up a VPC, security group, and database credentials) ourselves, but it's mostly standard boilerplate which is pretty well documented:</p><ul><li><a href='https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc.html'>Giving Lambda functions access to resources in an Amazon VPC</a>.</li><li><a href='https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-rds-dbinstance.html#aws-resource-rds-dbinstance--examples--Creating_a_Secrets_Manager_secret_for_a_master_password'>Creating a Secrets Manager secret for a master password</a>.</li></ul><p>You can see the full CloudFormation template <a href='https://github.com/paulbutcher/example-lambda-app2/blob/main/template.yaml'>here</a>. We'll explain the various sections in more detail below.</p><h3 id="vpc">VPC</h3><p>To avoid having to make our database publicly visible, we're going to put both our Lambda function and database in a shared VPC. Here's how we create that VPC:</p><pre class="language-yaml"><code class="lang-yaml language-yaml">  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
</code></pre><p>We also need to define a couple of subnets (RDS requires at least two subnets, in two different avaialability zones):</p><pre class="language-yaml"><code class="lang-yaml language-yaml">  Subnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: !Select &#91;0, Fn::GetAZs: !Ref &quot;AWS::Region&quot;&#93;
  Subnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.2.0/24
      AvailabilityZone: !Select &#91;1, Fn::GetAZs: !Ref &quot;AWS::Region&quot;&#93;
</code></pre><p>This is using a little CloudFormation magic to select the first two availability zones in whichever region we're deploying to. You could just as easily hardcode the availability zones if you prefer.</p><p>And we need a security group which allows things within the VPC to access Postgres:</p><pre class="language-yaml"><code class="lang-yaml language-yaml">  SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: !Sub &quot;Security group for ${AWS::StackName}&quot;
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 5432
          ToPort: 5432
          CidrIp: !GetAtt VPC.CidrBlock
</code></pre><p>We put our Lambda function in the VPC we've created by adding the following to its <code>Properties</code>:</p><pre class="language-yaml"><code class="lang-yaml language-yaml">      VpcConfig:
        SecurityGroupIds: &#91;!Ref SecurityGroup&#93;
        SubnetIds: &#91;!Ref Subnet1, !Ref Subnet2&#93;
      Policies: &#91;AWSLambdaVPCAccessExecutionRole&#93;
</code></pre><h3 id="database">Database</h3><p>We now have everything we need to create a database instance:</p><pre class="language-yaml"><code class="lang-yaml language-yaml">  DBSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: !Sub &quot;DBSubnet group for ${AWS::StackName}&quot;
      SubnetIds: &#91;!Ref Subnet1, !Ref Subnet2&#93;
  Database:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceClass: db.t4g.micro
      Engine: postgres
      EngineVersion: 14.15
      DBName: example&#95;lambda&#95;app
      AllocatedStorage: 20
      StorageEncrypted: true
      ManageMasterUserPassword: true
      MasterUsername: postgres
      KmsKeyId: !Ref DatabaseKey
      VPCSecurityGroups: &#91;!Ref SecurityGroup&#93;
      DBSubnetGroupName: !Ref DBSubnetGroup
</code></pre><p>Most of this is pretty obvious: we're creating an RDS database running on a <code>db.t4g.micro</code> instance, with 20GB of storage, encrypted at rest, and with a master user called <code>postgres</code>. We're adding it to the security group we created earlier, and letting it know about the subnets we created via a <code>DBSubnetGroup</code>.</p><h3 id="key_management">Key Management</h3><p>We've asked RDS to manage the database password for us (<code>ManageMasterUserPassword</code>) and store the credentials in a Secrets Manager (KMS) secret. Here's how we create that secret:</p><pre class="language-yaml"><code class="lang-yaml language-yaml">  DatabaseKey:
    Type: AWS::KMS::Key
    Properties:
      Description: DatabaseKey
      EnableKeyRotation: false
      KeyPolicy:
        Version: 2012-10-17
        Id: !Sub &quot;key-${AWS::StackName}&quot;
        Statement:
          - Effect: Allow
            Principal:
              AWS: !Sub &quot;arn:${AWS::Partition}:iam::${AWS::AccountId}:root&quot;
            Action: &#91;&quot;kms:&#42;&quot;&#93;
            Resource: &quot;&#42;&quot;
</code></pre><p>I've chosen to disable key rotation because I'll be passing the key to the Lambda function as an environment variable. An alternative would be to modify the Lambda function to use the Secrets Manager API to retrieve the password, but I wanted to keep the code as simple as possible. The rest is simple boilerplate taken from the article mentioned above.</p><p>To use this secret in our Lambda function, we add the following to the function's <code>Properties</code>:</p><pre class="language-yaml"><code class="lang-yaml language-yaml">      Environment:
        Variables:
          DB&#95;HOST: !GetAtt Database.Endpoint.Address
          DB&#95;PASSWORD: !Sub &quot;{{resolve:secretsmanager:${Database.MasterUserSecret.SecretArn}:SecretString:password}}&quot;
</code></pre><h3 id="deployment">Deployment</h3><p>Deploying is exactly the same as before: build the uberjar and then <code>sam deploy</code>. The first time you do this it'll take a while because it's creating the database instance, but subsequent deployments will be much quicker.</p>]]></content>
  </entry>
  <entry>
    <id>https://paulbutcher.com/lambda1.html</id>
    <link href="https://paulbutcher.com/lambda1.html"/>
    <title>Quick and Easy Clojure on AWS Lambda in 2025</title>
    <updated>2025-01-23T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<p>I recently found myself starting a new project and was looking for the quickest and easiest way to get something up and running. In the past I might have used <a href='https://www.heroku.com'>Heroku</a>, and I looked briefly at <a href='https://fly.io'>Fly.io</a>, but it turns out that Clojure now runs much better on Lambda than it used to (cold starts are no longer an issue), and it's easy to get up and running with <a href='https://aws.amazon.com/serverless/sam/'>AWS SAM</a> which gives us simple serverless Infrastructure as Code.</p><p>This article describes how to get a simple Clojure Ring application running. A <a href='lambda2.html'>followup article</a> shows how to connect it to a database. The code is available  <a href='https://github.com/paulbutcher/example-lambda-app'>here</a>.</p><h2 id="the_code">The Code</h2><p>Let's start with a simple Clojure Ring app with a sprinkling of interactivity through <a href='https://htmx.org'>HTMX</a>:</p><pre class="language-clojure"><code class="lang-clojure language-clojure">&#40;ns example.lambda-app
  &#40;:require &#91;compojure.core :refer &#91;defroutes GET&#93;&#93;
            &#91;compojure.route :as route&#93;
            &#91;hiccup2.core :refer &#91;html&#93;&#93;
            &#91;ring.logger :refer &#91;wrap-with-logger&#93;&#93;
            &#91;ring.middleware.defaults :refer &#91;site-defaults wrap-defaults&#93;&#93;
            &#91;ring.middleware.params :refer &#91;wrap-params&#93;&#93;&#41;&#41;

&#40;defn index-page
  &#91;&#93;
  &#40;str &#40;html &#91;:head &#91;:title &quot;HTMX Example&quot;&#93;
              &#91;:script {:src &quot;https://unpkg.com/htmx.org@2.0.4&quot;}&#93;&#93;
             &#91;:body &#91;:h1 &quot;HTMX Example&quot;&#93;
              &#91;:div#greeting {:hx-get &quot;/greet&quot; :hx-trigger &quot;load&quot;}&#93;&#93;&#41;&#41;&#41;

&#40;defn greet &#91;&#93; &#40;str &#40;html &#91;:div &quot;Hello, World!&quot;&#93;&#41;&#41;&#41;

&#40;defroutes app-routes
  &#40;GET &quot;/&quot; &#91;&#93; &#40;index-page&#41;&#41;
  &#40;GET &quot;/greet&quot; &#91;&#93; &#40;greet&#41;&#41;
  &#40;route/not-found &quot;Not Found&quot;&#41;&#41;

&#40;def app
  &#40;-&gt; app-routes
      wrap-params
      &#40;wrap-defaults site-defaults&#41;
      wrap-with-logger&#41;&#41;
</code></pre><p>This is all entirely standard: nothing different from any other Ring app. We're going to implement <i>two</i> different ways to serve this app, one using <code>ring-jetty-adapter</code> for local development, and one using <code>ring-lambda-adapter</code> for deployment to AWS Lambda.</p><p>For local development, we'll create <code>dev/user.clj</code>:</p><pre class="language-clojure"><code class="lang-clojure language-clojure">&#40;ns user
  &#40;:require &#91;ring.adapter.jetty :as jetty&#93;
            &#91;example.lambda-app :refer &#91;app&#93;&#93;&#41;&#41;

&#40;defn -main &#91;&amp; &#95;&#93;
  &#40;jetty/run-jetty #'app {:port 8080 :host &quot;0.0.0.0&quot; :join? false}&#41;&#41;
</code></pre><p>And for deployment to AWS Lambda, we'll create <code>lambda.clj</code>:</p><pre class="language-clojure"><code class="lang-clojure language-clojure">&#40;ns example.lambda
  &#40;:gen-class :implements
              &#91;com.amazonaws.services.lambda.runtime.RequestStreamHandler&#93;&#41;
  &#40;:require &#91;paulbutcher.ring-lambda-adapter :refer &#91;handle-request&#93;&#93;
            &#91;example.lambda-app :refer &#91;app&#93;&#93;&#41;&#41;

&#40;defn -handleRequest &#91;&#95; is os &#95;&#93; &#40;handle-request app is os&#41;&#41;
</code></pre><p>This implements the <code>RequestStreamHandler</code> interface defined by the AWS Java Lambda runtime. The <code>handle-request</code> function is provided by <code>ring-lambda-adapter</code> and does the work of converting the input and output streams to and from Ring requests and responses.</p><p>Finally, here's our <code>deps.edn</code>:</p><pre class="language-clojure"><code class="lang-clojure language-clojure">{:paths &#91;&quot;src&quot; &quot;resources&quot;&#93;
 :deps {com.amazonaws/aws-lambda-java-core {:mvn/version &quot;1.2.3&quot;}
        com.amazonaws/aws-xray-recorder-sdk-slf4j {:mvn/version &quot;2.18.2&quot;}
        com.paulbutcher/ring-lambda-adapter {:mvn/version &quot;1.0.7&quot;}
        compojure/compojure {:mvn/version &quot;1.7.1&quot;}
        hiccup/hiccup {:mvn/version &quot;2.0.0-RC4&quot;}
        org.clojure/clojure {:mvn/version &quot;1.12.0&quot;}
        ring-logger/ring-logger {:mvn/version &quot;1.1.1&quot;}
        ring/ring-core {:mvn/version &quot;1.13.0&quot;}
        ring/ring-defaults {:mvn/version &quot;0.5.0&quot;}}
 :aliases {:run {:main-opts &#91;&quot;-m&quot; &quot;user&quot;&#93;}
           :build {:deps {io.github.clojure/tools.build {:mvn/version &quot;0.10.6&quot;}}
                   :ns-default build}
           :dev {:extra-paths &#91;&quot;dev&quot;&#93;
                 :extra-deps {org.slf4j/slf4j-simple {:mvn/version &quot;2.0.16&quot;}
                              ring/ring-jetty-adapter {:mvn/version &quot;1.13.0&quot;}}}}}
</code></pre><p>This is all very standard apart from:</p><ul><li><code>aws-lambda-java-core</code> which provides the AWS Java Lambda runtime.</li><li><code>aws-xray-recorder-sdk-slf4j</code> which turns SLF4J logs into AWS X-Ray traces.</li><li><code>ring-lambda-adapter</code> which provides a Ring adapter for AWS Lambda.</li></ul><p>You should now be able to run locally with <code>clojure -M:dev:run</code>.</p><h2 id="deployment">Deployment</h2><p>To deploy to AWS, you'll need to have the <a href='https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html'>AWS SAM CLI installed</a>. This sits on top of AWS CloudFormation and simplifies the process of deploying serverless applications. Our application is described via a <code>template.yaml</code> file:</p><pre class="language-yaml"><code class="lang-yaml language-yaml">AWSTemplateFormatVersion: &quot;2010-09-09&quot;
Transform: AWS::Serverless-2016-10-31

Resources:
  Function:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: target/standalone.jar
      Handler: example.lambda::handleRequest
      Runtime: java21
      FunctionUrlConfig:
        AuthType: NONE
      AutoPublishAlias: live
      SnapStart:
        ApplyOn: PublishedVersions
      Timeout: 20
      MemorySize: 512
      Tracing: Active
    Metadata:
      SkipBuild: true

Outputs:
  Endpoint:
    Value: !GetAtt FunctionUrl.FunctionUrl
</code></pre><ul><li><code>CodeUri</code> points to an uberjar file we're going to build (the <code>SkipBuild</code> metadata tells SAM not to try to build the jar file itself).</li><li><code>Handler</code> is our Lambda function entry point.</li><li><code>AuthType</code> is <code>NONE</code> because this is a public web app (not an API that's sitting behind some kind of authentication).</li><li>We're only using a single alias (<code>live</code>), but we could have multiple aliases for different environments (e.g. staging etc.).</li><li><a href='https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html'><code>SnapStart</code></a> takes a snapshot of our function which reduces cold-start times to less than a second.</li><li><code>Tracing</code> enables AWS X-Ray tracing.</li></ul><p>To deploy, first build the jar file with <code>clojure -T:build uber</code> (see <a href='https://github.com/paulbutcher/example-lambda-app/blob/main/build.clj'><code>build.clj</code> in GitHub</a>), then deploy with <code>sam deploy --guided</code>. This will ask you some questions such as which region you want to deploy to and then eventually output the URL of your function's endpoint. Connect to that URL, and you should see exactly what you saw when you ran locally.</p><h2 id="monitoring">Monitoring</h2><p>There are a number of different ways to keep an eye on how your Lambda function is performing.</p><ul><li>You can watch logs locally in real time with <code>sam logs --tail</code>.<ul><li>You'll need to specify the region and stack name you already specified when deploying. You can avoid having to do so every time by adding a <code>&#91;default.global.parameters&#93;</code> section to your <code>samconfig.toml</code> file.</li></ul></li><li>From the AWS console, you can see logs in CloudWatch. Most interestingly, you can use X-Ray traces to see detailed timing information for each request.</li></ul><h2 id="development">Development</h2><p>Local development works just like any other Ring app. To deploy a new version, just build a new jar file and run <code>sam deploy</code>.</p><h2 id="conclusion">Conclusion</h2><p>The combination of SAM, which makes Lambda function deployment so simple, and SnapStart, which removes the cold start problem, means that AWS Lambda is my new default for getting started quickly.</p><p>In the <a href='lambda2.html'>next article</a>, we'll look at how to connect our Lambda function to a database.</p><h2 id="credits">Credits</h2><p>This was all heavily inspired by <a href='https://www.juxt.pro/blog/plain-clojure-lambda'>A Recipe for Plain Clojure Lambdas</a>.</p>]]></content>
  </entry>
  <entry>
    <id>https://paulbutcher.com/datalog4.html</id>
    <link href="https://paulbutcher.com/datalog4.html"/>
    <title>An introduction to Datalog in Flix: Part 4</title>
    <updated>2022-10-26T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<p>This is part 4 of a series. &#91;<a href='datalog1.html'>Part 1</a> | <a href='datalog2.html'>Part 2</a> | <a href='datalog3.html'>Part 3</a> | Part 4&#93;</p><p>The code to accompany this series is available <a href='https://github.com/paulbutcher/datalog-flix'>here</a>.</p><p>In the previous part of this series, we saw how to use lattice semantics to calculate all our degrees of separation within the Game of Thrones dataset in one pass. But we didn't quite get to our final solution because we weren't yet calculating counts of the number of characters at each degree.</p><p>In this part, we'll tie off that loose end, and discover why lattice semantics are "lattice" semantics in the process.</p><p>Of course, we could just count up our values in Flix (not Datalog) code, and that would be a perfectly reasonable approach. But as we'll see Datalog gives us a really elegant solution by leveraging <em>partial ordering</em>.</p><h2 id="partial_ordering">Partial Ordering</h2><p>So far we've been working with simple integers, and integers are (surprise!) <em>ordered</em>. So 1 is less than 2 and 3 is less than 126 and so on.</p><p>In fact, not only are integers ordered, they <em>totally</em> ordered. You can pick any pair of numbers <code>a</code> and <code>b</code>, and at least one of <code>a &lt;= b</code> or <code>b &lt;= a</code> will be true (they might both be true if <code>a</code> equals <code>b</code>).</p><p>But, not every set of values is totally ordered. A real world example of a partial ordering is ancestry; given two people a and b, it might easily be the case that <em>neither</em> "a is an ancestor of b" <em>nor</em> "b is an ancestor of a" is true.</p><p>For example, "Eddard Stark is an ancestor of Arya Stark" is true. But neither "Cersei Lannister is an ancestor of Tyrion Lannister" nor "Tyrion Lannister is an ancestor of Cersei Lannister" are true.</p><p>However, we can ask "who is the most recent common ancestor of Cersei and Tyrion" (in this case Tywin Lannister). We generally refer to this as the <em>least upper bound</em>.</p><h2 id="least_upper_bound">Least Upper Bound</h2><p>In part 3, we said that lattice semantics chose the "maximum" value from all possible values. This was a simplification: they actually chose the least upper bound.</p><p>For integers, which we were working with in part 3, the least upper bound <em>is</em> the maximum value. But for other types, those that are partially ordered (as we saw with ancestry above), the least upper bound could be something else.</p><p>An interesting example is sets. It may not be the case that either "set a is a subset of set b" or "set b is a subset of set a" is true. But they will always have a least upper bound which is the <em>union</em> of a and b.</p><p>For example, the least upper bound of <code>Set#{&quot;Tyrion Lannister&quot;, &quot;Cersei Lannister&quot;}</code> and <code>Set#{&quot;Tyrion Lannister&quot;, &quot;Arya Stark&quot;}</code> is <code>Set#{&quot;Tyrion Lannister&quot;, &quot;Cersei Lannister&quot;, &quot;Arya Stark&quot;}</code>.</p><blockquote><p> This is where the "lattice" in lattice semantics comes from: a partially ordered set which defines a least upper bound is called a <a href='https://en.wikipedia.org/wiki/Lattice_(order'><em>lattice</em></a>) in mathematics. </p></blockquote><p>Happily, this is exactly what we need to solve our degrees of separation problem.</p><h2 id="six_degrees_of_separation%2C_take_3">Six Degrees of Separation, Take 3</h2><p>As a reminder, here were the rules we used in part 3 of this series:</p><pre class="language-flix"><code class="lang-flix language-flix">        Degree&#40;x; Down&#40;0&#41;&#41; :- Root&#40;x&#41;.
        Degree&#40;x; n + Down&#40;1&#41;&#41; :- Degree&#40;y; n&#41;, Related&#40;y, x&#41;.
</code></pre><p>Here are the new rules we're going to add:</p><pre class="language-flix"><code class="lang-flix language-flix">        AggregatedDegree&#40;n; Set#{x}&#41; :- fix Degree&#40;x; n&#41;.
        DegreeCount&#40;n, Set.size&#40;s&#41;&#41; :- fix AggregatedDegree&#40;n; s&#41;.
</code></pre><p>We start by inferring new <code>AggregatedDegree</code> facts from the <code>Degree</code> facts we calculated previously. We're using the fact that the least upper bound of a collection of sets is the union of those sets, so the value on the right side of the semicolon will be the union of all of the character names in <code>Degree</code>.</p><blockquote><p> You might be wondering what the <code>fix</code> is for in our new rules? If you look at the two sides of the rule (either side of the <code>:-</code>) you can see that on the left we're using <code>n</code> as a normal value (it's on the left of the semicolon), whereas on the right it's a lattice value (it's on the right of the semicolon). Flix requires that we use <code>fix</code> if we ever mix a value this way; it ensures that we completely calculate all the <code>Degree</code> facts before starting to create <code>AggregateDegree</code> facts. </p></blockquote><p>So now we have a number of <code>AggregatedDegree</code> facts, one for each degree of separation, where the right hand side is a set of all the characters of that degree. The final step is to convert those facts into <code>DegreeCount</code> facts by finding the size of each set.</p><p>Here's the whole thing. As you can see, it's even more elegant than the solution we came up with in part 2 (which was already much simpler than we could have achieved without using Datalog).</p><pre class="language-flix"><code class="lang-flix language-flix">def main&#40;&#41;: Unit \ IO =

    let relationshipTypes = &quot;parents&quot; :: &quot;parentOf&quot; :: &quot;killed&quot; :: &quot;killedBy&quot; ::
        &quot;serves&quot; :: &quot;servedBy&quot; :: &quot;guardianOf&quot; :: &quot;guardedBy&quot; :: &quot;siblings&quot; ::
        &quot;marriedEngaged&quot; :: &quot;allies&quot; :: Nil;
    let relationships = Json.getRelationships&#40;relationshipTypes&#41;;

    let related = inject relationships into Related;

    let rules = #{
        Degree&#40;x; Down&#40;0&#41;&#41; :- Root&#40;x&#41;.
        Degree&#40;x; n + Down&#40;1&#41;&#41; :- Degree&#40;y; n&#41;, Related&#40;y, x&#41;.
        AggregatedDegree&#40;n; Set#{x}&#41; :- fix Degree&#40;x; n&#41;.
        DegreeCount&#40;n, Set.size&#40;s&#41;&#41; :- fix AggregatedDegree&#40;n; s&#41;.
    };

    let root = inject &quot;Tyrion Lannister&quot; :: Nil into Root;

    query rules, related, root select &#40;d, c&#41; from DegreeCount&#40;d, c&#41; |&gt;
        List.foreach&#40;match &#40;d, c&#41; -&gt; println&#40;&quot;Separated by degree ${d}: ${c}&quot;&#41;&#41;
</code></pre><p>And, for completeness, here's what it outputs:</p><pre class="language-flix"><code class="lang-flix language-flix">Separated by degree 6: 2
Separated by degree 5: 14
Separated by degree 4: 60
Separated by degree 3: 104
Separated by degree 2: 56
Separated by degree 1: 6
Separated by degree 0: 1
</code></pre><h2 id="conclusion">Conclusion</h2><p>That's it for our journey through Datalog and Flix. Please do experiment with other problems which can leverage Datalog: I'd love to see what you come up with!</p><p>&#91;<a href='datalog1.html'>Part 1</a> | <a href='datalog2.html'>Part 2</a> | <a href='datalog3.html'>Part 3</a> | Part 4&#93;</p>]]></content>
  </entry>
  <entry>
    <id>https://paulbutcher.com/datalog3.html</id>
    <link href="https://paulbutcher.com/datalog3.html"/>
    <title>An introduction to Datalog in Flix: Part 3</title>
    <updated>2022-10-25T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<p>This is part 3 of a series. &#91;<a href='datalog1.html'>Part 1</a> | <a href='datalog2.html'>Part 2</a> | Part 3 | <a href='datalog4.html'>Part 4</a>]</p><p>The code to accompany this series is available <a href='https://github.com/paulbutcher/datalog-flix'>here</a>.</p><h2 id="harder%2C_better%2C_faster%2C_stronger">Harder, Better, Faster, Stronger</h2><p>It's very common that we want to find the "best" solution to a problem. Perhaps we want the shortest route between two points? Or the fastest? Or the most efficient? Or...?</p><p>Flix's implementation of Datalog provides a feature known as "lattice semantics" (we'll see why "lattice" later) which allows us to solve exactly these kinds of problems. To illustrate, consider the following function:</p><pre class="language-flix"><code class="lang-flix language-flix">def foo&#40;&#41;: List&#91;&#40;String, Int32&#41;&#93; =
    let rules = #{
        Foo&#40;&quot;x&quot;, 1&#41;.
        Foo&#40;&quot;x&quot;, 2&#41;.
        Foo&#40;&quot;x&quot;, 5&#41;.
        Foo&#40;&quot;y&quot;, 2&#41;.
        Foo&#40;&quot;y&quot;, 3&#41;.
    };
    query rules select &#40;x, y&#41; from Foo&#40;x, y&#41;
</code></pre><p>This, unsurprisingly, just returns exactly the facts that we specified:</p><pre class="language-flix"><code class="lang-flix language-flix">&#40;x, 1&#41; :: &#40;x, 2&#41; :: &#40;x, 5&#41; :: &#40;y, 2&#41; :: &#40;y, 3&#41; :: Nil
</code></pre><p>But now, let's modify it so that it uses lattice semantics:</p><pre class="language-flix"><code class="lang-flix language-flix">def foo&#40;&#41;: List&#91;&#40;String, Int32&#41;&#93; =
    let rules = #{
        Foo&#40;&quot;x&quot;; 1&#41;.
        Foo&#40;&quot;x&quot;; 2&#41;.
        Foo&#40;&quot;x&quot;; 5&#41;.
        Foo&#40;&quot;y&quot;; 2&#41;.
        Foo&#40;&quot;y&quot;; 3&#41;.
    };
    query rules select &#40;x, y&#41; from Foo&#40;x; y&#41;
</code></pre><p>All we've done is replace the commas (<code>,</code>) in our original <code>Foo</code> rules with semicolons (<code>;</code>). What it now returns is:</p><pre class="language-flix"><code class="lang-flix language-flix">&#40;x, 5&#41; :: &#40;y, 3&#41; :: Nil
</code></pre><p>Switching to semicolons instructs Datalog to aggregate all the facts that have the same values on the left of the semicolon into a single fact, where the value on the right is the "maximum" of all the facts that are being combined. In our example above, the maximum value is 5 when the LHS is "x", and 3 when it's "y".</p><blockquote><p> There is some subtlety in what we mean when we say "maximum", as we'll see later, but for simple integers then what we get is exactly the same as if we had used <code>Int32.max</code>. </p></blockquote><p>It seems like a small change, but it's a small change that dramatically increases the power at our fingertips.</p><h2 id="minimums">Minimums</h2><p>Finding maximum values is great, but what if we want to find minimums instead? Flix allows us to reverse the sorting order of any type by using <code>Down</code>, so <code>Down&#91;Int32&#93;</code> sorts in the opposite order to <code>Int32</code>:</p><pre class="language-flix"><code class="lang-flix language-flix">flix&gt; 1 &lt; 3
true
flix&gt; 4 &lt; 2
false
flix&gt; Down&#40;1&#41; &lt; Down&#40;3&#41;
false
flix&gt; Down&#40;3&#41; &lt; Down&#40;2&#41;
true
</code></pre><p>Using <code>Down</code> in Datalog lattice semantics has exactly the effect you might imagine, allowing us to find minimum values instead of maximum values:</p><pre class="language-flix"><code class="lang-flix language-flix">def bar&#40;&#41;: List&#91;&#40;String, Down&#91;Int32&#93;&#41;&#93; =
    let rules = #{
        Bar&#40;&quot;x&quot;; Down&#40;1&#41;&#41;.
        Bar&#40;&quot;x&quot;; Down&#40;2&#41;&#41;.
        Bar&#40;&quot;x&quot;; Down&#40;5&#41;&#41;.
        Bar&#40;&quot;y&quot;; Down&#40;2&#41;&#41;.
        Bar&#40;&quot;y&quot;; Down&#40;3&#41;&#41;.
    };
    query rules select &#40;x, y&#41; from Bar&#40;x; y&#41;
</code></pre><p>Which returns:</p><pre class="language-flix"><code class="lang-flix language-flix">&#40;x, 1&#41; :: &#40;y, 2&#41; :: Nil
</code></pre><p>So much for theory, let's see how this helps us solve a real problem.</p><h2 id="six_degrees_of_separation%2C_take_2">Six Degrees of Separation, Take 2</h2><p>In <a href='datalog2.html'>part 2</a> of this series, we used Datalog to calculate degrees of separation between characters in Game of Thrones. The combination of logic programming and functional programming gave us a very simple solution. Now, we're going to use lattice semantics to make it even better.</p><p>As a refresher, here's the code from part 2 which creates our <code>Related</code> facts:</p><pre class="language-flix"><code class="lang-flix language-flix">    let relationshipTypes = &quot;parents&quot; :: &quot;parentOf&quot; :: &quot;killed&quot; :: &quot;killedBy&quot; ::
        &quot;serves&quot; :: &quot;servedBy&quot; :: &quot;guardianOf&quot; :: &quot;guardedBy&quot; :: &quot;siblings&quot; ::
        &quot;marriedEngaged&quot; :: &quot;allies&quot; :: Nil;
    let relationships = Json.getRelationships&#40;relationshipTypes&#41;;

    let related = inject relationships into Related;
</code></pre><p>And here is code which uses lattice semantics to calculate the degree of separation of every character from some root character (in this case Tyrion) in a single pass:</p><pre class="language-flix"><code class="lang-flix language-flix">    let rules = #{
        Degree&#40;x; Down&#40;0&#41;&#41; :- Root&#40;x&#41;.
        Degree&#40;x; n + Down&#40;1&#41;&#41; :- Degree&#40;y; n&#41;, Related&#40;y, x&#41;.
    };

    let root = inject &quot;Tyrion Lannister&quot; :: Nil into Root;

    println&#40;query rules, related, root select &#40;x, d&#41; from Degree&#40;x; d&#41;&#41;
</code></pre><p>Before we go through this to see how it works, here's the (truncated) output:</p><pre class="language-flix"><code class="lang-flix language-flix">&#40;Aegon Targaryen, 3&#41; :: &#40;Aeron Greyjoy, 3&#41; :: &#40;Aerys II Targaryen, 2&#41; ::
&#40;Akho, 3&#41; :: &#40;Alliser Thorne, 3&#41; :: &#40;Alton Lannister, 2&#41; :: ...
</code></pre><p>To see how this works, imagine what would happen if we wrote the above <em>without</em> lattice semantics:</p><pre class="language-flix"><code class="lang-flix language-flix">        Degree&#40;x, 0&#41; :- Root&#40;x&#41;.
        Degree&#40;x, n + 1&#41; :- Degree&#40;y, n&#41;, Related&#40;y, x&#41;.
</code></pre><p>This can be interpreted as saying: Character <code>x</code> is related to our root character by degree <code>n + 1</code> if we can find any character <code>y</code> which is related by degree <code>n</code>, and where <code>y</code> is related to <code>x</code>.</p><p>So Cersei, for example, is related to Tyrion by degree 1 because Tyrion is related to Tyrion by degree 0, and Tyrion is related to Cersei.</p><p>But ... Cersei is also related to Tyrion by degree 2 because Tywin is related to Tyrion by degree 1, and Tywin is related to Cercei. And Cersei is related to Tyrion by degree 3 because Jaime is related to Tyrion by degree 2, and Jaime is related to Cersei. And so on.</p><p>By contrast, Arya is not related to Tyrion at degree 1 or 2, but is related to him by degree 3, because Eddard Stark is related to Tyrion at degree 2, and Eddard is related to Arya. And Arya is related to Tyrion by degree 4 because Walder Frey is related to Tyrion at degree 3, and Walder is related to Arya. And so on.</p><p>So, as you can probably already see, with non-lattice semantics this will never terminate; we'll just keep calculating higher and higher degrees of separation until we run out of either memory or patience.</p><p>But, with lattice semantics (and given that we're using <code>Down</code> to reverse the ordering) we can constrain all of our degrees (the numbers on the right of the semicolon) to a single minimum value (whichever is the lowest they can ever take), which means:</p><ol><li>Our function terminates (always helpful!), and</li><li>The degree calculations always return the length of the "shortest path" from Tyrion to every other character.</li></ol><h2 id="conclusion">Conclusion</h2><p>So we're almost there: we now have a list of every character along with their minimum degree of separation from Tyrion. But if we're going to duplicate what we created in part 2, we need to go further and count how many characters there are at each degree of separation. We'll see how to do that in the <a href='datalog4.html'>next part</a> of this series.</p><p>&#91;<a href='datalog1.html'>Part 1</a> | <a href='datalog2.html'>Part 2</a> | Part 3 | <a href='datalog4.html'>Part 4</a>&#93;</p>]]></content>
  </entry>
  <entry>
    <id>https://paulbutcher.com/datalog2.html</id>
    <link href="https://paulbutcher.com/datalog2.html"/>
    <title>An introduction to Datalog in Flix: Part 2</title>
    <updated>2022-10-23T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<p>This is part 2 of a series. &#91;<a href='datalog1.html'>Part 1</a> | Part 2 | <a href='datalog3.html'>Part 3</a> | <a href='datalog4.html'>Part 4</a>]</p><p>The code to accompany this series is available <a href='https://github.com/paulbutcher/datalog-flix'>here</a>.</p><h2 id="injecting_facts">Injecting facts</h2><p>In part 1 of this series, we used Datalog rules to infer new facts about characters in Game of Thrones.</p><p>But where do our initial facts come from? In part 1 we simply included them as part of our Datalog, but this isn't a scalable approach. We don't want to have to manually re-enter all the details of all of the characters in Game of Thrones!</p><p>What's more likely is that we'll read these facts from some external source; perhaps a database or a JSON file. This is where the power of Flix integration comes into play; we can use Flix, a powerful general purpose language, to read our data and get it into the right format. We then <em>inject</em> it into Datalog facts.</p><p>So instead of writing this (from part 1):</p><pre class="language-flix"><code class="lang-flix language-flix">def main&#40;&#41;: Unit \ IO =
    let got = #{
        ParentOf&#40;&quot;Tywin Lannister&quot;, &quot;Cersei Lannister&quot;&#41;.
        ParentOf&#40;&quot;Tywin Lannister&quot;, &quot;Jaime Lannister&quot;&#41;.
        ParentOf&#40;&quot;Cersei Lannister&quot;, &quot;Joffrey Baratheon&quot;&#41;.
        ParentOf&#40;&quot;Cersei Lannister&quot;, &quot;Myrcella Baratheon&quot;&#41;.

        SiblingOf&#40;x, y&#41; :- ParentOf&#40;p, x&#41;, ParentOf&#40;p, y&#41;, if x != y.
    };
    let siblings = query got select &#40;x, y&#41; from SiblingOf&#40;x, y&#41;;
    println&#40;siblings&#41;
</code></pre><p>We can instead write:</p><pre class="language-flix"><code class="lang-flix language-flix">def main&#40;&#41;: Unit \ IO =
    let parentList = &#40;&quot;Tywin Lannister&quot;, &quot;Cersei Lannister&quot;&#41; ::
        &#40;&quot;Tywin Lannister&quot;, &quot;Jaime Lannister&quot;&#41; ::
        &#40;&quot;Cersei Lannister&quot;, &quot;Joffrey Baratheon&quot;&#41; ::
        &#40;&quot;Cersei Lannister&quot;, &quot;Myrcella Baratheon&quot;&#41; :: Nil;

    let parents = inject parentList into ParentOf;

    let got = #{
        SiblingOf&#40;x, y&#41; :- ParentOf&#40;p, x&#41;, ParentOf&#40;p, y&#41;, if x != y.
    };

    let siblings = query got, parents select &#40;x, y&#41; from SiblingOf&#40;x, y&#41;;

    println&#40;siblings&#41;
</code></pre><p>Or, more realistically, we read our data from some external file (in this case, Jeffrey Lancaster's amazingly detailed <a href='https://github.com/jeffreylancaster/game-of-thrones'>Game of Thrones dataset</a>):</p><pre class="language-flix"><code class="lang-flix language-flix">def main&#40;&#41;: Unit \ IO =

    let parents = inject Json.getParents&#40;&#41; into ParentOf;

    let got = #{
        SiblingOf&#40;x, y&#41; :- ParentOf&#40;p, x&#41;, ParentOf&#40;p, y&#41;, if x != y.
    };

    let siblings = query got, parents select &#40;x, y&#41; from SiblingOf&#40;x, y&#41;;

    println&#40;siblings&#41;
</code></pre><p>Which gives us the following (truncated!) output:</p><pre class="language-flix"><code class="lang-flix language-flix">&#40;Aegon Targaryen, Jon Snow&#41; :: &#40;Aegon Targaryen, Rhaenys Targaryen&#41; ::
&#40;Arya Stark, Bran Stark&#41; :: &#40;Arya Stark, Rickon Stark&#41; ::
&#40;Arya Stark, Robb Stark&#41; :: &#40;Arya Stark, Sansa Stark&#41; ::
&#40;Benjen Stark, Brandon Stark&#41; :: &#40;Benjen Stark, Eddard Stark&#41; :: ...
</code></pre><h2 id="chaining_datalog">Chaining Datalog</h2><p>The ability to move data back and forth between Datalog and Flix makes it very easy to use Datalog as part of solving a larger problem. To illustrate this, let's consider working out whether Game of Thrones obeys the <a href='https://en.wikipedia.org/wiki/Six_degrees_of_separation'>"six degrees of separation"</a> rule (the idea that all people are six or fewer connections away from each other; you might have come across it from the "Six Degrees of Kevin Bacon" game, or a mathematician's Erdős number).</p><p>As well as parentage, the dataset we've been using includes all kinds of other relationships between characters such as alliances, marriages and engagements, who serves whom, who killed whom, etc. Taking all of these relationships together, how many degrees of separation does it take from a major character (say Tyrion) to cover the entire cast of characters?</p><p>(You can find the complete source <a href='https://github.com/paulbutcher/datalog-flix/tree/master/part2-3'>here</a>).</p><p>First, we extract our long list of relationships from our dataset:</p><pre class="language-flix"><code class="lang-flix language-flix">    let relationshipTypes = &quot;parents&quot; :: &quot;parentOf&quot; :: &quot;killed&quot; :: &quot;killedBy&quot; ::
        &quot;serves&quot; :: &quot;servedBy&quot; :: &quot;guardianOf&quot; :: &quot;guardedBy&quot; :: &quot;siblings&quot; ::
        &quot;marriedEngaged&quot; :: &quot;allies&quot; :: Nil;
    let relationships = Json.getRelationships&#40;relationshipTypes&#41;;
</code></pre><p>We then inject that list into Datalog as a series of <code>Related</code> facts, just like we've seen above:</p><pre class="language-flix"><code class="lang-flix language-flix">    let related = inject relationships into Related;
</code></pre><p>So now we have a set of facts like <code>Related&#40;&quot;Tyrion Lannister&quot;, &quot;Shae&quot;&#41;</code> because Tyrion killed Shae, and <code>Related&#40;&quot;Arya Stark&quot;, &quot;Nymeria&quot;&#41;</code> because Arya is guarded by Nymeria, and so on.</p><p>Next, here is a Datalog rule which, given a set of characters we've already found, finds the characters with the next degree of separation:</p><pre class="language-flix"><code class="lang-flix language-flix">    let rules = #{
        NextDegree&#40;x&#41; :- AlreadyFound&#40;y&#41;, Related&#40;y, x&#41;, not AlreadyFound&#40;x&#41;.
    };
</code></pre><p>So a character <code>x</code> is in the next degree of separation if there is at least one character <code>y</code> who we have already and where <code>y</code> is related to <code>x</code>. Finally we exclude characters that we've already found.</p><p>Here's a function which uses the above to repeatedly calculate degrees of separation until we've exhausted all our characters:</p><pre class="language-flix"><code class="lang-flix language-flix">    def degreesOfSeparation&#40;deg: Int32, cs: List&#91;String&#93;&#41;: Unit \ IO = {
        let alreadyFound = inject cs into AlreadyFound;
        let nextDegree = query rules, alreadyFound, related select &#40;x&#41; from NextDegree&#40;x&#41;;
        match List.length&#40;nextDegree&#41; {
            case count if count &gt; 0 =&gt;
                println&#40;&quot;Separated by degree ${deg}: ${count}&quot;&#41;;
                degreesOfSeparation&#40;deg + 1, cs ::: nextDegree&#41;
            case &#95; =&gt;
                println&#40;&quot;Nobody separated by degree ${deg}&quot;&#41;
        }
    };
</code></pre><p>This function takes <code>deg</code> (a number representing the current degree of separation we're looking at) and <code>cs</code> a list of characters we've already found.</p><p>We start by creating our <code>AlreadyFound</code> facts from this list of characters, and then use the Datalog <code>rules</code> we defined above, along with our <code>AlreadyFound</code> and <code>Related</code> facts to generate <code>NextDegree</code> characters.</p><p><code>List.length&#40;nextDegree&#41;</code> returns the length of this list, and we use <code>match</code> to determine whether this number is greater than zero.</p><p>If it is, then we output the number of characters we just found, and recursively call <code>degreesOfSeparation</code> with <code>deg</code> increased by one, and a new set of characters which includes both our original root set and the characters we just found.</p><p>Finally, we kick the whole thing off by calling <code>degreesOfSeparation</code> with our initial root character, Tyrion:</p><pre class="language-flix"><code class="lang-flix language-flix">    degreesOfSeparation&#40;1, &quot;Tyrion Lannister&quot; :: Nil&#41;
</code></pre><p>Here's what we get when we run it:</p><pre class="language-flix"><code class="lang-flix language-flix">Separated by degree 1: 6
Separated by degree 2: 56
Separated by degree 3: 104
Separated by degree 4: 60
Separated by degree 5: 14
Separated by degree 6: 2
Nobody separated by degree 7
</code></pre><p>So yes, it does look like Game of Thrones does obey the six degrees of separation rule.</p><p>Here's the whole thing. I suggest trying to implement this in your favourite language to see just how easy the combination of Flix and Datalog makes this:</p><pre class="language-flix"><code class="lang-flix language-flix">def main&#40;&#41;: Unit \ IO =

    let relationshipTypes = &quot;parents&quot; :: &quot;parentOf&quot; :: &quot;killed&quot; :: &quot;killedBy&quot; ::
        &quot;serves&quot; :: &quot;servedBy&quot; :: &quot;guardianOf&quot; :: &quot;guardedBy&quot; :: &quot;siblings&quot; ::
        &quot;marriedEngaged&quot; :: &quot;allies&quot; :: Nil;
    let relationships = Json.getRelationships&#40;relationshipTypes&#41;;

    let related = inject relationships into Related;
    let rules = #{
        NextDegree&#40;x&#41; :- AlreadyFound&#40;y&#41;, Related&#40;y, x&#41;, not AlreadyFound&#40;x&#41;.
    };

    def degreesOfSeparation&#40;deg: Int32, cs: List&#91;String&#93;&#41;: Unit \ IO = {
        let alreadyFound = inject cs into AlreadyFound;
        let nextDegree = query rules, alreadyFound, related select &#40;x&#41; from NextDegree&#40;x&#41;;
        match List.length&#40;nextDegree&#41; {
            case count if count &gt; 0 =&gt;
                println&#40;&quot;Separated by degree ${deg}: ${count}&quot;&#41;;
                degreesOfSeparation&#40;deg + 1, cs ::: nextDegree&#41;
            case &#95; =&gt;
                println&#40;&quot;Nobody separated by degree ${deg}&quot;&#41;
        }
    };

    degreesOfSeparation&#40;1, &quot;Tyrion Lannister&quot; :: Nil&#41;
</code></pre><h2 id="conclusion">Conclusion</h2><p>Flix allows us to seamlessly move data back and forth between Flix and Datalog by <code>inject</code>ing facts from Flix to Datalog and <code>query</code>ing data from Datalog to Flix. This allows us to use the strengths of a general purpose language like Flix for things it's good at (e.g. reading JSON files) and Datalog for things that it's good at (e.g. inferring new facts from existing ones).</p><p>In the next part of this series, we'll look at one of the most powerful aspects of Flix's implementation of Datalog: lattice semantics.</p><p>&#91;<a href='datalog1.html'>Part 1</a> | Part 2 | <a href='datalog3.html'>Part 3</a> | <a href='datalog4.html'>Part 4</a>&#93;</p>]]></content>
  </entry>
  <entry>
    <id>https://paulbutcher.com/datalog1.html</id>
    <link href="https://paulbutcher.com/datalog1.html"/>
    <title>An introduction to Datalog in Flix: Part 1</title>
    <updated>2022-10-22T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<p>This is part 1 of a series. &#91;Part 1 | <a href='datalog2.html'>Part 2</a> | <a href='datalog3.html'>Part 3</a> | <a href='datalog4.html'>Part 4</a>&#93;</p><p>The code to accompany this series is available <a href='https://github.com/paulbutcher/datalog-flix'>here</a>.</p><h2 id="flix">Flix</h2><p><a href='https://flix.dev'>Flix</a> is an exciting new programming language which provides the power of strongly typed functional programming with the accessibility of "programmer friendly" languages like Go, Rust, or Ruby.</p><p>This article isn't about Flix, though, it's about Datalog, and the reason why Flix plus Datalog creates something greater than the sum of its parts.</p><h2 id="logic_programming">Logic Programming</h2><p>Logic programming is one of the "big three" programming language paradigms:</p><p><strong>Imperative programming</strong>: Languages like C, C++, Java, JavaScript, Go, Kotlin, …</p><p><strong>Functional programming</strong>: Languages like Haskell, Clojure, Elixir, F#, …</p><p><strong>Logic programming</strong>: Prolog, Datalog, Answer-set Programming, Mercury, …</p><p>But ... if it's one of the three major programming paradigms, how come nobody uses it? Perhaps you created a couple of toy Prolog programs at college, but you've almost certainly not used it since then.</p><p>There are good reasons why logic programming hasn't caught on outside of a very few specialised areas, but that may be about to change. By including logic programming as a first-class element of the language, Flix allows us to seamlessly move between functional and logic programming, leveraging the strengths of both.</p><p>This is analogous to the way that C# embeds database queries directly in the language through LINQ (and of course, you don't use LINQ to implement every single method; instead you use C# for most of your code and drop into LINQ when it makes sense).</p><p>In this first article, we'll explore the basics of Datalog. And then in the rest of the series we'll see how the combination of Datalog and Flix brings huge expressive power.</p><h2 id="facts">Facts</h2><p>Datalog programs are built from two components: <em>facts</em> and <em>rules</em>. Here are some facts about Game of Thrones:</p><pre class="language-flix"><code class="lang-flix language-flix">GreatHouse&#40;&quot;Stark&quot;&#41;.
GreatHouse&#40;&quot;Targaryen&quot;&#41;.

ParentOf&#40;&quot;Rhaegar Targaryen&quot;, &quot;Jon Snow&quot;&#41;.
ParentOf&#40;&quot;Aerys II Targaryen&quot;, &quot;Daenerys Targaryen&quot;&#41;.

Coordinates&#40;&quot;Kings Landing&quot;, 6.697, 12.759&#41;.
Coordinates&#40;&quot;Winterfell&quot;, 5.666, 6.218&#41;.
</code></pre><p>You can read these facts as:</p><ul><li>Stark is one of the Great Houses.</li><li>Rhaegar Targaryen is a parent of Jon Snow.</li><li>Kings Landing is located at coordinates 6.697, 12.759.</li></ul><p>A fact can have any number of terms of (almost) any type.</p><h2 id="rules">Rules</h2><p>Rules create new facts by making logical inferences from existing facts. Imagine, for example, that we know the following facts:</p><pre class="language-flix"><code class="lang-flix language-flix">ParentOf&#40;&quot;Tywin Lannister&quot;, &quot;Cersei Lannister&quot;&#41;.
ParentOf&#40;&quot;Tywin Lannister&quot;, &quot;Jaime Lannister&quot;&#41;.
ParentOf&#40;&quot;Cersei Lannister&quot;, &quot;Joffrey Baratheon&quot;&#41;.
ParentOf&#40;&quot;Cersei Lannister&quot;, &quot;Myrcella Baratheon&quot;&#41;.
</code></pre><p>Then we can create additional facts about who is who's grandparent with the following rule:</p><pre class="language-flix"><code class="lang-flix language-flix">GrandparentOf&#40;x, y&#41; :- ParentOf&#40;x, c&#41;, ParentOf&#40;c, y&#41;.
</code></pre><p>Which you can read as "<code>x</code> is a grandparent of <code>y</code> <strong>if</strong> we can find at least one person <code>c</code> where <code>x</code> is a parent of <code>c</code>, <strong>and</strong> <code>c</code> is a parent of <code>y</code>".</p><p>Here's a complete Flix program which does this:</p><pre class="language-flix"><code class="lang-flix language-flix">def main&#40;&#41;: Unit \ IO =
    let got = #{
        ParentOf&#40;&quot;Tywin Lannister&quot;, &quot;Cersei Lannister&quot;&#41;.
        ParentOf&#40;&quot;Tywin Lannister&quot;, &quot;Jaime Lannister&quot;&#41;.
        ParentOf&#40;&quot;Cersei Lannister&quot;, &quot;Joffrey Baratheon&quot;&#41;.
        ParentOf&#40;&quot;Cersei Lannister&quot;, &quot;Myrcella Baratheon&quot;&#41;.

        GrandparentOf&#40;x, y&#41; :- ParentOf&#40;x, c&#41;, ParentOf&#40;c, y&#41;.
    };
    let grandparents = query got select &#40;x, y&#41; from GrandparentOf&#40;x, y&#41;;
    println&#40;grandparents&#41;
</code></pre><p>The code within the <code>#{ ... }</code> block is our datalog, the rest of the code is the Flix program that it's embedded within. Our Datalog program is executed when we call <code>query</code> to extract the new <code>GrandparentOf</code> facts.</p><p>Here's what it outputs:</p><pre class="language-flix"><code class="lang-flix language-flix">&#40;Tywin Lannister, Joffrey Baratheon&#41; :: &#40;Tywin Lannister, Myrcella Baratheon&#41; :: Nil
</code></pre><p>This is a list of 2-element tuples, with <code>::</code> indicating the list "cons" operator and <code>Nil</code> the end of the list. We can interpret these results as saying that Tywin Lannister is the grandparent of both Joffrey Baratheon and Myrcella Baratheon.</p><p>Here's a slightly different program which uses the same facts to generate additional facts about siblings:</p><pre class="language-flix"><code class="lang-flix language-flix">def main&#40;&#41;: Unit \ IO =
    let got = #{
        ParentOf&#40;&quot;Tywin Lannister&quot;, &quot;Cersei Lannister&quot;&#41;.
        ParentOf&#40;&quot;Tywin Lannister&quot;, &quot;Jaime Lannister&quot;&#41;.
        ParentOf&#40;&quot;Cersei Lannister&quot;, &quot;Joffrey Baratheon&quot;&#41;.
        ParentOf&#40;&quot;Cersei Lannister&quot;, &quot;Myrcella Baratheon&quot;&#41;.

        SiblingOf&#40;x, y&#41; :- ParentOf&#40;p, x&#41;, ParentOf&#40;p, y&#41;.
    };
    let siblings = query got select &#40;x, y&#41; from SiblingOf&#40;x, y&#41;;
    println&#40;siblings&#41;
</code></pre><p>The key line is:</p><pre class="language-flix"><code class="lang-flix language-flix">SiblingOf&#40;x, y&#41; :- ParentOf&#40;p, x&#41;, ParentOf&#40;p, y&#41;.
</code></pre><p>Which you can read as "<code>x</code> is a sibling of <code>y</code> <strong>if</strong> we can find at least one person <code>p</code> where <code>p</code> is a parent of <code>x</code> <strong>and</strong> <code>p</code> is a parent of <code>y</code>".</p><p>And here's what it outputs:</p><pre class="language-flix"><code class="lang-flix language-flix">&#40;Cersei Lannister, Cersei Lannister&#41; :: &#40;Cersei Lannister, Jaime Lannister&#41; ::
&#40;Jaime Lannister, Cersei Lannister&#41; :: &#40;Jaime Lannister, Jaime Lannister&#41; ::
&#40;Joffrey Baratheon, Joffrey Baratheon&#41; :: &#40;Joffrey Baratheon, Myrcella Baratheon&#41; ::
&#40;Myrcella Baratheon, Joffrey Baratheon&#41; :: &#40;Myrcella Baratheon, Myrcella Baratheon&#41; ::
Nil
</code></pre><p>Were you surprised that there were so many answers?</p><p>The list is as long as it is because:</p><ol><li>If <code>SiblingOf&#40;x, y&#41;</code> is true, then so is <code>Sibling&#40;y, x&#41;</code> (i.e. if you are my sibling, then I am also your sibling).</li><li>As we've written it, <code>Sibling</code> considers anyone with a parent to be their own sibling.</li></ol><p>The first point above is probably exactly what we want (i.e. we really do want the sibling relationship to be reflexive). But perhaps we don't want people being their own siblings.</p><p>Here's a slightly modified version of our program which adds a <em>guard</em> to our rule, which eliminates cases where <code>x</code> and <code>y</code> represent the same person:</p><pre class="language-flix"><code class="lang-flix language-flix">def main&#40;&#41;: Unit \ IO =
    let got = #{
        ParentOf&#40;&quot;Tywin Lannister&quot;, &quot;Cersei Lannister&quot;&#41;.
        ParentOf&#40;&quot;Tywin Lannister&quot;, &quot;Jaime Lannister&quot;&#41;.
        ParentOf&#40;&quot;Cersei Lannister&quot;, &quot;Joffrey Baratheon&quot;&#41;.
        ParentOf&#40;&quot;Cersei Lannister&quot;, &quot;Myrcella Baratheon&quot;&#41;.

        SiblingOf&#40;x, y&#41; :- ParentOf&#40;p, x&#41;, ParentOf&#40;p, y&#41;, if x != y.
    };
    let siblings = query got select &#40;x, y&#41; from SiblingOf&#40;x, y&#41;;
    println&#40;siblings&#41;
</code></pre><p>And here's what it outputs:</p><pre class="language-flix"><code class="lang-flix language-flix">&#40;Cersei Lannister, Jaime Lannister&#41; :: &#40;Jaime Lannister, Cersei Lannister&#41; ::
&#40;Joffrey Baratheon, Myrcella Baratheon&#41; :: &#40;Myrcella Baratheon, Joffrey Baratheon&#41; ::
Nil
</code></pre><h2 id="conclusion">Conclusion</h2><p>A Datalog program consists of <em>facts</em> and <em>rules</em>. Rules generate new facts from existing ones.</p><p>In the <a href='datalog2.html'>next part</a> of this series, we'll dig deeper into the integration between Flix and Datalog.</p><p>&#91;Part 1 | <a href='datalog2.html'>Part 2</a> | <a href='datalog3.html'>Part 3</a> | <a href='datalog4.html'>Part 4</a>&#93;</p>]]></content>
  </entry>
</feed>
