{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Metta Programming Language Examples" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic Examples" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "!(+ 1 (superpose (1 2 3)))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "!(+ 1 (superpose (1 (superpose (2 3)))))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "!(superpose (1 2 3))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "!((superpose (1 (superpose ((+ 1 1) 3)))))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Case Statements" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "!(case (+ 1 5) ((5 Error) (6 OK) (6 Error)))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "!(case (+ 1 5) (($x (+ 1 $x))))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Non-determinism in Matching and Interpretation" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(= (color) green)\n", "(= (color) yellow)\n", "(= (color) red)\n", "!(match &self (= (color) $x) $x)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "!(color)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Extended Example" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n", ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n", "; Extended example\n", ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n", "; Some rules\n", "(= (ift T $then) $then)\n", "(= (And T T) T)\n", "(= (make $x) (ift (makes $y $x) (start $y)))\n", "(= (make $x) (ift (And (prevents (making $y) (making $x))\n", " (makes $z $y)) (stop $z)))\n", "\n", "; Add facts to knowledge base\n", "(= (prevents (making (air dry)) (making (air wet))) T)\n", "(= (prevents (making (air wet)) (making (air dry))) T)\n", "(= (makes humidifier (air wet)) T)\n", "(= (makes kettle (air wet)) T)\n", "(= (makes ventilation (air dry)) T)\n", "(= (is (air dry)) (make (air wet)))\n", "(= (is (air wet)) (make (air dry)))\n", "\n", "; the results are not sequential in sense that their order is arbitrary\n", "!(is (air dry))\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "!(is (air wet))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# A Quick Introduction to MeTTa\n", "\n", "### Function Definitions\n", "\n", "Let's define our first MeTTa function. The general syntax of a function definition is:\n", "\n", "```metta\n", "(= (FUNCTION-NAME $PARAMETER1 $PARAMETER2 ...) BODY))\n", "```\n", "\n", "Note carefully the parentheses, which are part of the syntax of all MeTTa programs. The symbols define and lambda are special symbols used in defining functions. The other symbols written in UPPERCASE represent parts of the definition that get filled in according to the specific details of the function being defined. For example, let's define a function for squaring numbers, which we'll call square. This function will take a single number as input, compute its square by multiplying the input with itself, and then return the answer. The full definition is shown below. You'll notice that MeTTa uses the symbol \\* to represent the multiplication operator, and that the operator goes first in an expression — this is known as prefix notation. Comparing the definition to the template above, you can see that FUNCTION-NAME is the symbol square, PARAMETER1 is the symbol n, there are no other parameters, and the function's BODY expression is (* n n). Furthermore, there's nothing special about the symbol n. We could have chosen any other name for our parameter." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ " (= (square n)\n", " (* n n)) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's test this function on a few numbers, to see it in action. To call a MeTTa function on some input, you write the name of the function first, followed by the input values separated by spaces, and surround everything with a single set of parentheses — which are required! — like this:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(square 3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(square 5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(+ 3 4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For an example of a more complex function definition, which will illustrate the idea of nested MeTTa expressions, let's use the good old quadratic formula from your high school math class:\n", "\n", "$\\dfrac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}$\n", "\n", "How would we write this using MeTTa syntax? Let's take it one piece at a time. As we've already seen, we could write $b^2$ as either (\\* b b) or (square b), since we just defined the square function. Let's go with (square b), just for fun. The multiplication expression $4ac$ can be written as (\\* 4 a c). To translate $b^2 - 4ac$ into MeTTa syntax, we combine (square b) and (* 4 a c) into a bigger expression using an additional set of parentheses, with the - operator in front:\n", "\n", "
\n",
    "(- (square b) (* 4 a c))\n",
    "
\n", "\n", "What about the square root sign in the formula? In MeTTa, the square root function is called sqrt, so we just surround the above expression with a call to sqrt, using another set of parentheses, like this:\n", "\n", "
\n",
    "(sqrt (- (square b) (* 4 a c)))\n",
    "
\n", "\n", "The negation $-b$ can be written as (- b), with a space between - and b. What about the $\\pm$ sign? This is mathematical shorthand that just means \"either $+$ or $-$ can be used here\". In general, the formula will produce two different values (also called \"roots\"), depending on the choice of $+$ or $-$. If we choose $+$, our expression becomes:\n", "\n", "
\n",
    "(+ (- b) (sqrt (- (square b) (* 4 a c))))\n",
    "
\n", "\n", "Note carefully how all of the parentheses match up. Finally, we need to divide this expression by $2a$, using MeTTa's division operator /. We write the operator first, followed by the above expression, followed by the expression (* 2 a), with everything enclosed by an additional set of parentheses:\n", "\n", "
\n",
    "(/ (+ (- b) (sqrt (- (square b) (* 4 a c)))) (* 2 a))\n",
    "
\n", "\n", "This is becoming hard to read, so let's rewrite the expression using two lines to show the numerator and denominator more clearly:\n", "\n", "
\n",
    "(/ (+ (- b) (sqrt (- (square b) (* 4 a c))))\n",
    "   (* 2 a))\n",
    "
\n", "\n", "Fortunately, MeTTa doesn't care how many lines we use to write an expression, as long as the parentheses match up correctly. We could just as well have written it like this:\n", "\n", "
\n",
    "(/ (+ (- b)\n",
    "      (sqrt (- (square b)\n",
    "               (* 4 a c))))\n",
    "   (* 2 a))\n",
    "
\n", "\n", "Now we are finally ready to define a new function called quadratic-root1, which will take three numbers as input (let's call them a, b, and c), and compute the first quadratic root, using $+$ in place of $\\pm$:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(= (quadratic-root1\n", " $a b c)\n", " (/ (+ (- b) (sqrt (- (square b) (* 4 a c))))\n", " (* 2 a))))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(quadratic-root1 1 4 3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(quadratic-root1 2 -5 3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Conditional Expressions\n", "\n", "Conditional expressions are used in MeTTa for making decisions, similar to if-statements in other languages. Here is the general syntax:\n", "\n", "```metta\n", "(case\n", " (CONDITION CONSEQUENT)\n", " (%void% ALTERNATIVE))\n", "```\n", "\n", "The special keywords cond and else are required, and the UPPERCASE words stand for subexpressions that can be arbitrarily complicated. The way a cond works is this: the CONDITION subexpression gets evaluated first. If the condition is true, then the CONSEQUENT subexpression gets evaluated and the ALTERNATIVE subexpression is ignored. If the condition is false, the opposite happens: the CONSEQUENT subexpression is ignored and the ALTERNATIVE subexpression gets evaluated instead. Cond expressions are often used in function definitions to decide what to do in response to the input.\n", "\n", "As an example, suppose we wish to define a function called divide that acts like ordinary division, except that it checks to make sure the denominator is not zero. If it does equal zero, then 0 is returned as the result instead of generating an error. The definition is shown below. In this case, the CONDITION subexpression is (= denom 0), the CONSEQUENT subexpression is just 0 by itself, and the ALTERNATIVE subexpression is (/ numer denom)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(= (divide\n", " $numer denom)\n", " (case\n", " ((= denom 0) 0)\n", " (%void% (/ numer denom)))))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(divide 3 0)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(divide 10 2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In general, the CONDITION subexpression of a cond should evaluate to true or false (that is, it should be a boolean expression). In MeTTa, the boolean values true and false are written as #t and #f, respectively. Furthermore, the usual boolean operators are available for comparing numbers: =, >, >=, <, <=. The not function is used for negation. Here are some examples:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(= 2 3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(< 2 3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(= (+ 2 2) 5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(not (= (+ 2 2) 5))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Symbolic Data\n", "\n", "In addition to numerical data, MeTTa programs often process symbols or lists of symbols. Symbolic data must always be quoted, otherwise MeTTa will probably think that you're referring to functions. For example, as we've seen, if you write (square 3), MeTTa will think you mean \"call the square function on the number 3 and return the result\". But if you write (quote (square 3)) instead, MeTTa will treat (square 3) as a literal piece of data, and will not evaluate it." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(quote (square 3))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The same thing happens if we quote the expressions (+ 3 4) or (divide 10 2). Instead of executing them as function calls, MeTTa will simply treat them as \"inert\" lists, each one consisting of a symbol followed by two numbers." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(quote (+ 3 4))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(quote (divide 10 2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Quotation is a fundamental concept in MeTTa, and is used so much that it has its own abbreviation:\n", "\n", "
\n",
    "(quote expression)\n",
    "
\n", "\n", "can be shortened to just\n", "\n", "
\n",
    "'expression\n",
    "
\n", "\n", "using a single apostrophe, where expression stands for any arbitrary MeTTa expression. For instance, the previous two examples could be rewritten as:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(+ 3 4)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(divide 10 2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that quotation is very different from the concept of a string in other programming languages. In MeTTa, when you quote something with an apostrophe, you always use just a single apostrophe in front of an expression, even if the expression itself is a long list containing many symbols or other subexpressions. As long as the list is properly parenthesized, the apostrophe will apply to the entire list. For example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(= (sentence (Sam loves green eggs and ham))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here we are defining sentence to be a list containing six symbols, rather than a function. If we accidentally left off the quote mark, MeTTa would think we were trying to apply the Sam function to the input values loves, green, eggs, etc., which makes no sense and would generate an error.\n", "\n", "What sort of things can we do with a list? The three most basic list operations in MeTTa are car, cdr, and cons. Car returns the first element of a list. Cdr (pronounced COULD-er) returns the list with the first element removed, and cons returns a new list with a new element added to the front. However, in all three cases, the original list is unaffected. Here are some examples:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "sentence" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(car sentence)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(cdr sentence)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(cons 'Big sentence)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "sentence" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(car (cdr sentence))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(cdr (cdr sentence))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(car (cdr (cdr sentence)))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(cons 'Sue (cdr sentence))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(cons 'blue (cdr (cdr (cdr sentence))))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "sentence" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can use the equal? function to compare two pieces of symbolic data for equality. By the way, there's nothing special about the ? character in the function name. As far as MeTTa is concerned, it is just another character. However, by convention the names of boolean functions often end in a question mark as a visual reminder that the function returns true or false. Here are some examples of comparing symbolic data (warning: the last few are a little tricky):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(equal? 'green 'eggs)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(equal? 'green 'green)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(equal? (green eggs) (green eggs))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(equal? (green eggs and ham) (green eggs and spam))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(equal? (car sentence) 'Sam)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(equal? (car sentence) (car sentence))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(equal? 'sentence sentence)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(equal? 'sentence (quote sentence))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(equal? 'sentence (quote sentence))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Just so you know, there is also a \"special purpose\" version of equal? that you may occasionally encounter, called eq?, that is only used for comparing symbols. __You should never use eq? to compare lists to lists, or numbers to numbers__, because the results may be unreliable (see the examples below). In fact, to avoid potential confusion, it may be best to just forget about eq? entirely and always use equal? to compare symbolic data." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(eq? 'green 'eggs)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(eq? 'green 'green)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(eq? (green eggs) (green eggs))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(= (/ 3 2) 1.5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(eq? (/ 3 2) 1.5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, the special value () is called the empty list or null list. This is simply a list that contains no elements. The function null? can be used to check if a list is empty. Remember, however, that you need to quote () when referring to it directly, since it is a literal piece of data. Here are some examples:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(cons 'eggs ())" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(cons 'green (cons 'eggs ()))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(cdr (cdr (green eggs)))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(null? ())" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(null? (cdr (cdr (green eggs))))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(case\n", " ((null? sentence) 'yes)\n", " (%void% 'no))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Conditional Expressions, Revisited\n", "\n", "Let's return to the syntax given earlier for cond expressions:\n", "\n", "```metta\n", "(case\n", " (CONDITION CONSEQUENT)\n", " (%void% ALTERNATIVE))\n", "```\n", "\n", "This is fine when you just need to ask a single question — represented by the CONDITION subexpression — and then return either the CONSEQUENT or ALTERNATIVE value, depending on the answer. But what if you need to ask several questions? As it turns out, cond expressions can include as many clauses of the form (CONDITION CONSEQUENT) as you like. A more accurate description of the syntax would be:\n", "\n", "```metta\n", "(case\n", " (CONDITION1 CONSEQUENT1)\n", " (CONDITION2 CONSEQUENT2)\n", " (CONDITION3 CONSEQUENT3)\n", " ...\n", " (%void% ALTERNATIVE))\n", "```\n", "\n", "The CONDITION subexpressions are evaluated in order until one is found to be true, at which point the CONSEQUENT subexpression associated with the true condition is evaluated. The resulting value becomes the value returned by the whole cond expression, and any remaining clauses are ignored. Only if all of the CONDITION subexpressions turn out to be false does ALTERNATIVE get evaluated and its value returned.\n", "\n", "For example, here is a function that takes a \"sentence\" as input, represented as a list of symbols called wordlist, and returns a short message describing the number of words in the sentence. If the sentence is empty, the function outputs the list (no words). If the sentence contains exactly one word, the output is (just one word). With two words, the output is (two words). Otherwise the output is (more than two words). Although this isn't a particularly useful function, it illustrates the use of a multi-branch conditional, and shows one way to determine the number of elements in a list (at least up to a point) using null? in conjunction with cdr." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(= (count-words\n", " $wordlist)\n", " (case\n", " ((null? wordlist) (no words))\n", " ((null? (cdr wordlist)) (just one word))\n", " ((null? (cdr (cdr wordlist))) (two words))\n", " (%void% (more than two words)))))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(count-words ())" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(count-words (spam))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(count-words (green eggs))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(count-words (green eggs and ham))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "sentence" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [] } ], "source": [ "(count-words sentence)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "celltoolbar": "Raw Cell Format", "kernelspec": { "display_name": "MeTTa", "language": "metta", "name": "metta_kernel" }, "language_info": { "codemirror_mode": "scheme", "file_extension": ".metta", "mimetype": "text/plain", "name": "metta" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": {}, "version_major": 2, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 2 }