<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Pete Tsamouris</title>
    <description>The latest articles on Forem by Pete Tsamouris (@petets).</description>
    <link>https://forem.com/petets</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F292435%2Ffc495260-6426-4a7a-aebf-b595188b8e6a.png</url>
      <title>Forem: Pete Tsamouris</title>
      <link>https://forem.com/petets</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/petets"/>
    <language>en</language>
    <item>
      <title>Unison.IO</title>
      <dc:creator>Pete Tsamouris</dc:creator>
      <pubDate>Mon, 17 Feb 2020 15:00:44 +0000</pubDate>
      <link>https://forem.com/petets/unison-io-3k9</link>
      <guid>https://forem.com/petets/unison-io-3k9</guid>
      <description>&lt;h4&gt;
  
  
  Before we begin!
&lt;/h4&gt;

&lt;p&gt;Quick reminder that &lt;code&gt;Unison&lt;/code&gt; is still in &lt;code&gt;public alpha&lt;/code&gt;! &lt;/p&gt;

&lt;p&gt;Parts of the language, testing functionality and libraries that appear in this post might be subject to change.&lt;/p&gt;

&lt;p&gt;In the following post I will do my best to refer to command-line user &lt;em&gt;input and output&lt;/em&gt; as &lt;em&gt;I/O&lt;/em&gt; when in free text mode, which also seems to be the preferred term of the Unison documentation and guide. In code snippets, the ability will be referred to as &lt;code&gt;IO&lt;/code&gt; with the &lt;code&gt;base.io.&lt;/code&gt; namespace omitted for brevity.&lt;/p&gt;

&lt;h5&gt;
  
  
  Problem statement: I/O operations in Unison.
&lt;/h5&gt;

&lt;p&gt;I will try and frame the problem statement as a BDD scenario:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GIVEN An individual interested in the Unison PL
WHEN  That individual investigates I/O
THEN  They have an brief document available to guide them
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I will concede at this point that the &lt;em&gt;real&lt;/em&gt; problem statement is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GIVEN I have done I/O before on numerous occasions
WHEN  I need to remind myself yet again how to do it
THEN  I have my notes kept somewhere
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;😇 and 🤦‍♀️&lt;/p&gt;

&lt;h5&gt;
  
  
  Do I need to understand &lt;a href="https://www.unisonweb.org/docs/language-reference#abilities"&gt;abilities&lt;/a&gt; in depth to do I/O?
&lt;/h5&gt;

&lt;p&gt;Strictly speaking: to get acquainted with I/O you will have to get acquainted with abilities.&lt;/p&gt;

&lt;p&gt;If all you care to do is at this point is "read some input from the console and write some output to it" an &lt;em&gt;in depth&lt;/em&gt; understanding of what abilities are or how they are handled internally is &lt;em&gt;strictly&lt;/em&gt; not necessary. I have however helpfully added the documentation link for your convenience, as some familiarity with the syntax and the moving parts is necessary.&lt;/p&gt;

&lt;h5&gt;
  
  
  How does &lt;code&gt;ucm&lt;/code&gt; run a program?
&lt;/h5&gt;

&lt;p&gt;Let's have a quick look at an excerpt of the output of the &lt;code&gt;ucm help&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ucm help

...
  ucm run .mylib.mymain
  Executes the definition `.mylib.mymain` from the codebase, then exits.

  ucm run.file foo.u mymain
  Executes the definition called `mymain` in `foo.u`, then exits.
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ucm&lt;/code&gt; can be asked to &lt;code&gt;run&lt;/code&gt; an existing codebase definition if pointed to an entity via its full namespace path. Furthermore the &lt;code&gt;run.file&lt;/code&gt; flag type-checks the file &lt;code&gt;ucm&lt;/code&gt; is pointed to and then runs the existing codebase definition.&lt;/p&gt;

&lt;p&gt;At the time of writing for &lt;code&gt;ucm&lt;/code&gt; to run an entity it must have a type of &lt;code&gt;'{ IO } ()&lt;/code&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  So single ticks and curly braces?
&lt;/h5&gt;

&lt;p&gt;It might look strange at first but abilities amongst other things are meant to allow "the same syntax for programs that do (asynchronous) I/O", to quote the documentation. In other languages you might see a signature like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;f :  Int =&amp;gt; Unit&lt;/code&gt; for a synchronous function&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;f :  Int =&amp;gt; IO [Unit]&lt;/code&gt; for a function that performs IO&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One could observe that "sure &lt;code&gt;IO&lt;/code&gt; involves input and output" but is that synchronous or asynchronous?&lt;/p&gt;

&lt;p&gt;By using abilities and handlers the requirement for asynchronous context during the steps in the body of &lt;code&gt;f&lt;/code&gt; would be expressed as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;f: Int -&amp;gt; {e} ()&lt;/code&gt; (&lt;code&gt;e&lt;/code&gt; being the empty set of abilities)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;f: Int -&amp;gt; {IO} ()&lt;/code&gt; (still synchronous but involves I/O)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;f: Int -&amp;gt; '{IO} ()&lt;/code&gt; (asynchronous and involves I/O)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While trying to not stray and discuss abilities in general, for the strict scope of I/O the last remaining bit to explain is the single tick. It denotes a &lt;a href="https://www.unisonweb.org/docs/language-reference#delayed-computations"&gt;delayed computation&lt;/a&gt; which is the Unison way of doing asynchronous computations.&lt;/p&gt;

&lt;h5&gt;
  
  
  How can I get &lt;code&gt;IO&lt;/code&gt; (the Unison ability) in my codebase ?
&lt;/h5&gt;

&lt;p&gt;At the time of writing &lt;code&gt;IO&lt;/code&gt; comes as part of the &lt;code&gt;ucm&lt;/code&gt; &lt;code&gt;base&lt;/code&gt; package that can be pulled while running &lt;code&gt;ucm&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.&amp;gt; pull https://github.com/unisonweb/base .base
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  And what can &lt;code&gt;IO&lt;/code&gt; do ?
&lt;/h5&gt;

&lt;p&gt;A complete list of what &lt;code&gt;IO&lt;/code&gt; can do can be found by means of looking under &lt;code&gt;base.io&lt;/code&gt;. The focus for a simple &lt;code&gt;input-manipulate-output&lt;/code&gt; program will be the two functions that allow reading and writing to the console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;base.io.readLine : '{IO} Text
base.io.printLine : Text -&amp;gt;{IO} ()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  So how that documentation example?
&lt;/h5&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use io

program : '{IO} ()
program = 'let
  printLine "What is your name?"
  name = !readLine
  printLine ("Hello, " ++ name)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;the function is declared as a delayed side effect &lt;code&gt;'{IO} ()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the body must begin with a "delayed let"&lt;/li&gt;
&lt;li&gt;delayed calls must be forced with &lt;code&gt;!&lt;/code&gt; in this instance &lt;code&gt;!readLine&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It might seem a bit heavy to digest in one go but what you have at this point is a &lt;em&gt;program&lt;/em&gt; that performs I/O by using the mechanics of the &lt;code&gt;IO&lt;/code&gt; ability. The syntax is such that functions that require synchronous &lt;code&gt;IO&lt;/code&gt; are called directly whereas functions that require asynchronous &lt;code&gt;IO&lt;/code&gt; are forced (at the "end of the world" when the I/O is handled by the runtime).&lt;/p&gt;

&lt;h5&gt;
  
  
  Run it!
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Copy paste the code into &lt;code&gt;scratch.u&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;add&lt;/code&gt; the &lt;code&gt;program&lt;/code&gt; function as an entity in your codebase (its namespace will be &lt;code&gt;.&lt;/code&gt; by default, so it will live under &lt;code&gt;.program&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Followed by one of these commands:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ucm run.file scratch.u program&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ucm run .program&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The output will be something along these lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ucm run .program

What is your name?
X 
Hello, X
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>unison</category>
      <category>functional</category>
      <category>alphatest</category>
      <category>io</category>
    </item>
    <item>
      <title>Packing consecutive list elements</title>
      <dc:creator>Pete Tsamouris</dc:creator>
      <pubDate>Wed, 05 Feb 2020 17:13:51 +0000</pubDate>
      <link>https://forem.com/petets/packing-consecutive-list-elements-329e</link>
      <guid>https://forem.com/petets/packing-consecutive-list-elements-329e</guid>
      <description>&lt;h4&gt;
  
  
  Before we begin!
&lt;/h4&gt;

&lt;p&gt;Quick reminder that &lt;code&gt;Unison&lt;/code&gt; is still in &lt;code&gt;public alpha&lt;/code&gt;! &lt;/p&gt;

&lt;p&gt;Parts of the language, testing functionality and libraries that appear in this post might be subject to change.&lt;/p&gt;

&lt;h5&gt;
  
  
  &lt;a href="https://wiki.haskell.org/99_questions/1_to_10"&gt;Exercise 9&lt;/a&gt;: Pack consecutive duplicates into sublists
&lt;/h5&gt;

&lt;p&gt;The aim of the &lt;code&gt;pack&lt;/code&gt; function is to take a list of type &lt;code&gt;[a]&lt;/code&gt; and group all consecutive duplicate elements into sublists, the output type being &lt;code&gt;[[a]]&lt;/code&gt;. At the same time, the &lt;code&gt;unpack&lt;/code&gt; function reverses the packing the aim being to allow for better ease of testing (more on this below) .&lt;/p&gt;

&lt;p&gt;Please note the use of the term &lt;em&gt;sublist&lt;/em&gt; for every list embedded in the outer list, for example in &lt;code&gt;[[1], [2, 2], [3]]&lt;/code&gt; each of &lt;code&gt;[1]&lt;/code&gt;, &lt;code&gt;[2, 2]&lt;/code&gt; and &lt;code&gt;[3]&lt;/code&gt; will be referred to as a &lt;em&gt;sublist&lt;/em&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  How will we know we have built the right thing?
&lt;/h5&gt;

&lt;p&gt;Let's consider &lt;code&gt;pack&lt;/code&gt; first:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An empty list still needs to return a &lt;code&gt;[[a]]&lt;/code&gt; (yet technically &lt;code&gt;[]&lt;/code&gt; and &lt;code&gt;[[]]&lt;/code&gt; both type-check against &lt;code&gt;[[a]])&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Any single element list &lt;code&gt;[x]&lt;/code&gt; will be wrapped in a list to form a sublist: &lt;code&gt;[[x]]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Generalising the previous property: a list of non duplicate elements will end up with each element wrapped in a single element list.&lt;/li&gt;
&lt;li&gt;The minimum list containing a duplicate element &lt;code&gt;[x, x]&lt;/code&gt; will see the elements wrapped in a single sublist: &lt;code&gt;[[x, x]]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;So in the most general case any list consisting of consecutive duplicate and non consecutive duplicate elements will end up with sublists where &lt;code&gt;length &amp;gt; 1&lt;/code&gt;, as well as sublists where &lt;code&gt;length == 1&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's now have a look at &lt;code&gt;unpack&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Any list containing an empty list (&lt;code&gt;[[]]&lt;/code&gt;) will unpack to &lt;code&gt;[]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Consecutive sublists, regardless of the number of elements in each, will be concatenated to a flattened list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From a property based perspective:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For any &lt;em&gt;not packed&lt;/em&gt; list &lt;em&gt;U&lt;/em&gt; the length of &lt;em&gt;U&lt;/em&gt; will be equal to the sum of the lengths of the sublists that are contained in the &lt;em&gt;packed&lt;/em&gt; list &lt;em&gt;P&lt;/em&gt;, where &lt;em&gt;pack U produces P&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Any list &lt;em&gt;L&lt;/em&gt; that can be packed to a list &lt;em&gt;P&lt;/em&gt; can subsequently be unpacked to a resulting list &lt;em&gt;L'&lt;/em&gt;  with the two lists &lt;em&gt;L == L'&lt;/em&gt; being equal.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  On testing:
&lt;/h5&gt;

&lt;p&gt;Having recently been made aware of the &lt;code&gt;check&lt;/code&gt; and &lt;code&gt;check'&lt;/code&gt; test helpers I  will be making use of them to write my unit and property tests from now on.&lt;/p&gt;

&lt;p&gt;For reference the tour (for the time being!) only mentions &lt;code&gt;expect&lt;/code&gt; and &lt;code&gt;run (expect (...))&lt;/code&gt; but the &lt;code&gt;check&lt;/code&gt; and &lt;code&gt;check'&lt;/code&gt; functions can also be used to yield slightly more concise test cases.&lt;/p&gt;

&lt;h5&gt;
  
  
  Let's write some tests then!
&lt;/h5&gt;

&lt;p&gt;Lets add the signatures of &lt;code&gt;pack&lt;/code&gt; and &lt;code&gt;unpack&lt;/code&gt; and implement a minimum hard coded and clearly wrong version, only to allow the compiler to run the tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use .base

pack : [a] -&amp;gt; [[a]]
pack as = []

unpack : [[a]] -&amp;gt; [a]
unpack aa = []
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here are the unit tests for &lt;code&gt;pack&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test&amp;gt; test.pack.empty = 
  check (pack [] == [])

test&amp;gt; test.pack.single = 
  check (pack [1] == [[1]])

test&amp;gt; test.pack.duplicate = 
  check (pack [1, 1] == [[1, 1]])

test&amp;gt; test.pack.list = 
  check (pack [1, 2, 2, 3, 4, 4] == [[1], [2, 2], [3], [4, 4]])
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And here are the unit tests for &lt;code&gt;unpack&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test&amp;gt; test.unpack.empty = 
  check (unpack [[]] == [])

test&amp;gt; test.unpack.empty' = 
  check (unpack [] == [])

test&amp;gt; test.unpack.single = 
  check (unpack [[1]] == [1])

test&amp;gt; test.unpack.duplicate = 
  check (unpack [[1, 1]] == [1, 1])

test&amp;gt; test.unpack.list = 
  check (unpack [[1], [2, 2], [3], [4, 4]] == [1, 2, 2, 3, 4, 4])
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  Repetitive much?
&lt;/h5&gt;

&lt;p&gt;You might have noticed a ...slight repetition in the testing department. I am allowing a slight peek in the test-case-writing-process on purpose to better highlight why property tests might be helpful in this instance. Since the &lt;code&gt;pack&lt;/code&gt; and &lt;code&gt;unpack&lt;/code&gt; methods take us from &lt;code&gt;[a]&lt;/code&gt; to &lt;code&gt;[[a]]&lt;/code&gt; and back again, instead of testing &lt;code&gt;pack&lt;/code&gt; with a set of inputs and outputs then &lt;code&gt;unpack&lt;/code&gt; with the set of outputs as inputs it is (usually) quicker to test both at the same time using the approach sometimes referred to as &lt;a href="https://fsharpforfunandprofit.com/posts/property-based-testing-2/#there-and-back"&gt;there and back again&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A quick &lt;code&gt;find&lt;/code&gt; for generators under &lt;code&gt;base.v1.test&lt;/code&gt; reveals that a small number of additional generators would come handy in our case to allow freedom to better shape the test inputs to our needs.&lt;/p&gt;

&lt;p&gt;Originally I wrote a non empty list generator (inspired from the stock &lt;code&gt;list&lt;/code&gt; generator, with the range being always a minimum two elements) as well as a consecutive elements list generator, that when forced produces a list containing exclusively consecutive elements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;base.test.v1.non_empty_list : '{Gen} a -&amp;gt; '{Gen} [a]
base.test.v1.non_empty_list g =
  'let
    size = !nat
    List.map (_ -&amp;gt; !g) (range 1 (size + 2))

base.test.v1.consecutive_list: '{Gen} a -&amp;gt; '{Gen} [a]
base.test.v1.consecutive_list g = 
  ' let
      size = increment (!nat)
      elem = !g
      List.map (_ -&amp;gt; elem) (range 1 (size + 2))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Then&lt;/em&gt; I noticed the lack of reuse between the two functions as well as general lack of information being communicated at the type level and most importantly, at this point the codebase contains 3 more or less identical functions for &lt;code&gt;list&lt;/code&gt;, with slightly different arguments. &lt;/p&gt;

&lt;p&gt;Slight detour to use a non empty list &lt;em&gt;type&lt;/em&gt; for the above, by making use of Unison &lt;a href="https://www.unisonweb.org/docs/language-reference#record-types"&gt;record types&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type NonEmptyList a = { head' : a, tail' : [a]}

toList : NonEmptyList a -&amp;gt; [a]
toList nel = case nel of
  NonEmptyList.NonEmptyList hd tl -&amp;gt; [hd] ++ tl

base.test.v1.nel : '{Gen} a -&amp;gt; '{Gen} (NonEmptyList a)
base.test.v1.nel g = 'let NonEmptyList !g !(list g) 

base.test.v1.consecutive_nel : '{Gen} a -&amp;gt; '{Gen} (NonEmptyList a)
base.test.v1.consecutive_nel g = 
  'let 
    non_empty = !(nel g)
    hd = head' non_empty
    NonEmptyList (hd) ([hd] ++ tail' non_empty)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So a &lt;code&gt;consecutive_nel&lt;/code&gt; is produced in terms of a &lt;code&gt;nel&lt;/code&gt;, while &lt;code&gt;head'&lt;/code&gt; is added to the scope by &lt;code&gt;Unison&lt;/code&gt; by the definition of the record type members &lt;code&gt;head'&lt;/code&gt; and &lt;code&gt;tail'&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;base.test.v1.unpacked_list: '{Gen} [Nat]
base.test.v1.unpacked_list =
  'let
    large = pick ['((!nat) + 10), '((!nat) + 100)]
    small = pick ['((!nat) + 1), '((!nat) + 10)]
    s1 = !(nel large)
    m1 = !(consecutive_nel small)
    join (map toList [m1, s1, m1, s1])
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Is this overly complex? Maybe, but I would like to be able to produce input-lists for my tests containing clearly discernible elements so I can be sure to notice if I break the generator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; sample 100 '(!unpacked_list)
   ⧩
   [ [1, 1, 10, 1, 1, 10],
     [1, 1, 10, 10, 10, 10],
     [10, 10, 10, 1, 1, 10],
     [10, 10, 10, 10, 10, 10],
     [1, 1, 10, 1, 1, 100],
     [1, 1, 10, 10, 10, 100],
     [10, 10, 10, 1, 1, 100],
     ...
     truncated

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note: &lt;code&gt;'(!(list nat))&lt;/code&gt; produces some lists with consecutive values due to the nature and behaviour of the &lt;code&gt;nat&lt;/code&gt; generator,  but this behaviour cannot be relied upon. The &lt;code&gt;{Gen}&lt;/code&gt; ability handlers are not random number generators but rather domain enumerators in specific order and the same holds for how &lt;code&gt;pick&lt;/code&gt; selects a generator from the list too.&lt;/p&gt;

&lt;h5&gt;
  
  
  So what about the properties then?
&lt;/h5&gt;

&lt;p&gt;In order to minimise the code and since all property tests are meant to test the same properties mentioned already (length of sub-lists equal to the unpacked list, &lt;code&gt;unpack . pack&lt;/code&gt; produces the input), it is handy to write a &lt;code&gt;test generator&lt;/code&gt; that given a &lt;code&gt;generator&lt;/code&gt; for a list of some structure, checks if the properties hold over a number of iterations tested.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use base.Nat +
use base.Nat map

subListLengths: [[a]] -&amp;gt; Nat
subListLengths aas = foldl (+) 0 (map size aas)

test : '{Gen} [a] -&amp;gt; '{Gen} Test
test generator = 
  'let
    l = !(generator)
    packed = pack l
    unpacked = unpack packed
    check' ((unpacked == l) &amp;amp;&amp;amp; (subListLengths packed == size unpacked))

test&amp;gt; test.pack_unpack.empty = 
  check (((unpack . pack) []) == [])

test&amp;gt; test.pack_unpack.list =
  runs 100 (test (list nat))

test&amp;gt; test.pack_unpack.consecutive = 
  runs 100 (test unpacked_list)

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Caveat: &lt;code&gt;runs 100 (test (list nat))&lt;/code&gt; probably has more brackets than I care to write. It also took a number of attempts to get it to type-check, but I suppose this will get more intuitive given time and practice.&lt;/p&gt;

&lt;h5&gt;
  
  
  After a day spent writing tests, could we "pack" a list maybe?
&lt;/h5&gt;

&lt;p&gt;In the past I have attempted my best to implement the function that is the main focus of the exercise in as many ways as possible. In this instance I feel that there are only so many ways that are worthwhile, and some of them rely on (currently) missing standard library functions. I will only implement &lt;code&gt;pack&lt;/code&gt; in terms of &lt;code&gt;takeWhile&lt;/code&gt; and &lt;code&gt;dropWhile&lt;/code&gt; (which I have unit tested previously, and are beyond our scope at this point):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;base.List.dropWhile : (a -&amp;gt; Boolean) -&amp;gt; [a] -&amp;gt; [a]
base.List.dropWhile pred as =
  case as of
    []              -&amp;gt; []
    h +: t | pred h -&amp;gt; dropWhile pred t
    _               -&amp;gt; as

base.List.takeWhile : (a -&amp;gt; Boolean) -&amp;gt; [a] -&amp;gt; [a]
base.List.takeWhile pred as =
  case as of
    []              -&amp;gt; []
    h +: t | pred h -&amp;gt; [h] ++ takeWhile pred t
    h +: _          -&amp;gt; []
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pack : [a] -&amp;gt; [[a]]
pack as = case as of
  []  -&amp;gt; []
  h +: t -&amp;gt; (h +: (takeWhile (e -&amp;gt; e == h) t)) +: pack (dropWhile (e -&amp;gt; e == h) as)

unpack : [[a]] -&amp;gt;[a]
unpack = join
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It helps that &lt;code&gt;unpack&lt;/code&gt; is actually provided for free with the Unison &lt;code&gt;base&lt;/code&gt; library. In case you don't have it immediately handy to check the implementation, here's how you can concatenate a list containing sublists into a flat list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.&amp;gt; view base.List.join

  base.List.join : [[a]] -&amp;gt; [a]
  base.List.join =
    use List ++
    foldl (++) []


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  But are the tests and properties passing?
&lt;/h5&gt;

&lt;p&gt;Why don't we find out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.&amp;gt; test

  ✅

    New test results:

  ◉ test.pack.empty                 : Proved.
  ◉ test.pack.single                : Proved.
  ◉ test.pack.duplicate             : Proved.
  ◉ test.pack.list                  : Proved.

  ◉ test.unpack.empty               : Proved.
  ◉ test.unpack.empty'              : Proved.
  ◉ test.unpack.single              : Proved.
  ◉ test.unpack.list                : Proved.

  ◉ test.pack_unpack.empty          : Proved.
  ◉ test.pack_unpack.list           : Proved.
  ◉ test.unpack.duplicate           : Proved.
  ◉ test.pack_unpack.consecutive    : Proved.


  ✅ 12 test(s) passing

  Tip: Use view test.pack_unpack.empty to view the source of a
       test.

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Turns out yes they are, so that's a wrap!&lt;/p&gt;

</description>
      <category>unison</category>
      <category>functional</category>
      <category>alphatest</category>
    </item>
    <item>
      <title>Property based testing in Unison</title>
      <dc:creator>Pete Tsamouris</dc:creator>
      <pubDate>Tue, 21 Jan 2020 18:01:05 +0000</pubDate>
      <link>https://forem.com/petets/property-based-testing-in-unison-2knp</link>
      <guid>https://forem.com/petets/property-based-testing-in-unison-2knp</guid>
      <description>&lt;h4&gt;
  
  
  Property testing in Unison
&lt;/h4&gt;

&lt;p&gt;Quick reminder that &lt;code&gt;Unison&lt;/code&gt; is still in &lt;code&gt;public alpha&lt;/code&gt;! &lt;/p&gt;

&lt;p&gt;Parts of the language, testing functionality and libraries that appear in this post might be subject to change.&lt;/p&gt;

&lt;h5&gt;
  
  
  On properties
&lt;/h5&gt;

&lt;p&gt;There are a lot of very good resources on property testing &lt;a href="https://dev.to/jdsteinhauser/intro-to-property-based-testing-2cj8"&gt;out there&lt;/a&gt; with some pointing to a number of different &lt;a href="https://fsharpforfunandprofit.com/posts/property-based-testing-2/"&gt;approaches&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Depending on whom you ask and what your current level of familiarity is, identifying properties of the code being delivered may fall under the "easier said than done" column. I will use the &lt;code&gt;compress&lt;/code&gt; function from my previous blog post &lt;a href="https://dev.to/petets/eliminate-consecutive-duplicates-57hi"&gt;"Eliminate consecutive duplicates"&lt;/a&gt; to try and highlight what the process might look like. &lt;/p&gt;

&lt;p&gt;This post is meant to help the reader explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;property based testing as a concept and practice.&lt;/li&gt;
&lt;li&gt;the Unison programming language.&lt;/li&gt;
&lt;li&gt;just how easy it is to write property tests in Unison.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Remind me about &lt;code&gt;compress&lt;/code&gt; real quick?
&lt;/h5&gt;

&lt;p&gt;Being parametric on type &lt;code&gt;a&lt;/code&gt; when given an input-list &lt;code&gt;[a]&lt;/code&gt; &lt;code&gt;compress&lt;/code&gt; will remove consecutive elements in the list, if any exist. Do not be afraid of some level of formality: for two lists &lt;code&gt;[1, 2, 3]&lt;/code&gt; and [&lt;code&gt;1, 1, 1&lt;/code&gt;], the former would be classed as &lt;code&gt;non compressible&lt;/code&gt;, whereas the latter would be classed as &lt;code&gt;compressible&lt;/code&gt;. The result of the compression being the output-list &lt;code&gt;[1]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the previous blog post I implemented &lt;code&gt;compress&lt;/code&gt; in multiple ways and here's the one I want to test using property tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;base.List.compress: [a] -&amp;gt; [a]
base.List.compress as = case as of
  [] -&amp;gt; []
  [x] -&amp;gt; [x]
  [x, y] ++ rest -&amp;gt;
    if (x == y) then base.List.compress (y +: rest)
    else x +: base.List.compress (y +: rest)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  What will be our testing criterion?
&lt;/h5&gt;

&lt;p&gt;In the following section, &lt;em&gt;C&lt;/em&gt; denotes a compressible list, and &lt;em&gt;U&lt;/em&gt; a list that cannot be compressed. A list is compressible if after &lt;code&gt;compress&lt;/code&gt; is applied to it, the output-list contains less elements than the input. &lt;/p&gt;

&lt;p&gt;This is an arbitrarily picked criterion and different criteria could be selected, hence why I called it "our" criterion. Another criterion might be that an input-list &lt;em&gt;U&lt;/em&gt; would be equal to the output-list &lt;em&gt;U&lt;/em&gt;. &lt;/p&gt;

&lt;h5&gt;
  
  
  What are (some of) the properties of &lt;code&gt;compress&lt;/code&gt;?
&lt;/h5&gt;

&lt;h6&gt;
  
  
  Non compressible list properties
&lt;/h6&gt;

&lt;ul&gt;
&lt;li&gt;The minimum &lt;em&gt;U&lt;/em&gt; list is the empty list.&lt;/li&gt;
&lt;li&gt;Any list &lt;code&gt;[x]&lt;/code&gt; (containing a single element) is equally not compressible.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;U ++[x]&lt;/em&gt; will be non compressible, for any value &lt;code&gt;x&lt;/code&gt; as long as &lt;code&gt;x&lt;/code&gt; is not equal to the last element. &lt;/li&gt;
&lt;li&gt;The above can be generalised so that &lt;em&gt;U ++ U&lt;/em&gt; will be compressible if the head and tail of &lt;em&gt;U&lt;/em&gt; are the same element.&lt;/li&gt;
&lt;li&gt;Inversely: removing elements one at a time from a &lt;em&gt;U&lt;/em&gt; list and finally reaching the point of the empty list, produces a sequence of &lt;em&gt;U&lt;/em&gt; lists.&lt;/li&gt;
&lt;/ul&gt;

&lt;h6&gt;
  
  
  Compressible list properties
&lt;/h6&gt;

&lt;ul&gt;
&lt;li&gt;For each element &lt;code&gt;x&lt;/code&gt;, the list &lt;code&gt;[x, x]&lt;/code&gt; is the minimum non empty &lt;em&gt;C&lt;/em&gt; list.&lt;/li&gt;
&lt;li&gt;The above can be generalised in two ways: 

&lt;ul&gt;
&lt;li&gt;The &lt;em&gt;U&lt;/em&gt; list containing &lt;code&gt;head +: tail&lt;/code&gt; can be converted to a &lt;em&gt;C&lt;/em&gt; list by means of the operation &lt;code&gt;[head, head] ++ tail&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;The &lt;em&gt;U&lt;/em&gt; list containing &lt;code&gt;init :+ last&lt;/code&gt; can be converted to a &lt;em&gt;C&lt;/em&gt; list by means of the operation &lt;code&gt;init ++ [last, last]&lt;/code&gt;. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Unrelated to the cornercase above, &lt;em&gt;C ++ [x]&lt;/em&gt; will be compressible, for any value &lt;code&gt;x&lt;/code&gt; regardless of whether &lt;code&gt;x&lt;/code&gt; is equal to the last element of &lt;em&gt;C&lt;/em&gt; or not (as the compressible section does not need to be in the end). &lt;/li&gt;
&lt;li&gt;Generalising the above: &lt;em&gt;C ++ U&lt;/em&gt; is compressible, just like &lt;em&gt;U ++ C&lt;/em&gt; is compressible, just like &lt;em&gt;C ++ C&lt;/em&gt; is compressible.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;U ++ U&lt;/em&gt; will be compressible if the head and tail of &lt;em&gt;U&lt;/em&gt; are the same element.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whether a list can be compressed or not is all about content. As long as the equal consecutive elements are always one next to the other, a class of list manipulation operations like reversing will not affect the ability of the list to compress or not.&lt;/p&gt;

&lt;p&gt;The lists of properties above might not necessarily be exhaustive but we have more than a few to work with. Note that properties are a mathematical concept so there is a certain degree of lack of formal notation and formal definition in the section above, as well as some leaps in logic that might not hold water from a strict mathematical perspective. The focus of this post however is not math, but Unison.&lt;/p&gt;

&lt;h5&gt;
  
  
  Now what about &lt;code&gt;Unison&lt;/code&gt; specifically?
&lt;/h5&gt;

&lt;p&gt;The relevant section of the documentation can be found in the Unison &lt;a href="https://www.unisonweb.org/docs/tour#a-property-based-test"&gt;tour&lt;/a&gt;. Please follow the link and have a read!&lt;/p&gt;

&lt;p&gt;Here is a step by step breakdown of what the pieces involved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;use .base.test.v1&lt;/code&gt; statement. &lt;/li&gt;
&lt;li&gt;Each line that declares a property test must begin with &lt;code&gt;test&amp;gt;&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;The &lt;code&gt;test&amp;gt;&lt;/code&gt; expression is followed by the name of the test this "path" reflects the namespace under which the test will be added.&lt;/li&gt;
&lt;li&gt;The property itself, as in the content of the &lt;code&gt;go&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;A call to the &lt;code&gt;runs&lt;/code&gt; function specifying how many times to run which test, in the example, &lt;code&gt;100 go&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  I know that the addition of natural numbers is &lt;a href="https://en.wikipedia.org/wiki/Associative_property"&gt;associative&lt;/a&gt;!
&lt;/h5&gt;

&lt;p&gt;And here is one way to prove that the natural number addition assosiative property holds in &lt;code&gt;Unison&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use builtin.Nat +

test&amp;gt; tests.base.Nat.associative = 
  go _ = a = !nat
         b = !nat
         c = !nat
         expect (((a + b) + c) == (a + (b + c)))
  runs 100 go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  What just happened?
&lt;/h5&gt;

&lt;p&gt;There is a Unison &lt;a href="https://www.unisonweb.org/docs/tour#syntax-notes"&gt;syntax guide&lt;/a&gt; that is part of the tour:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ucm&lt;/code&gt; had a hard time time finding out which of all the functions called &lt;code&gt;+&lt;/code&gt; the code was referring to, so it was guided to pick the one for natural numbers by the &lt;code&gt;use&lt;/code&gt; statement.&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;delayed ability&lt;/em&gt; to generate a natural number (&lt;code&gt;nat&lt;/code&gt;) was &lt;em&gt;forced&lt;/em&gt; with the exclamation mark syntax (&lt;code&gt;!nat&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Which means that the &lt;code&gt;nat&lt;/code&gt; function, for each call, produced one natural number.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;expect&lt;/code&gt; function was used to test the property.&lt;/li&gt;
&lt;li&gt;The property was expressed as a boolean equality check.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;go&lt;/code&gt; function and contained code block is the test, and it ignores its first argument &lt;code&gt;_&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Ignoring the first argument is the mechanism in &lt;code&gt;Unison&lt;/code&gt; to make a function lazy (caveat: if my understanding of the documentation is correct).&lt;/li&gt;
&lt;li&gt;The aptly named &lt;code&gt;runs&lt;/code&gt; function is what actually "runs" the "property" 100 times.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  What building blocks does Unison provide?
&lt;/h5&gt;

&lt;p&gt;&lt;code&gt;Unison&lt;/code&gt; comes with generators that are exposed by the &lt;code&gt;Gen&lt;/code&gt; ability under the &lt;code&gt;base.test.v1&lt;/code&gt; namespace to produce values of given types. We can build on top of the &lt;code&gt;nat&lt;/code&gt; and &lt;code&gt;list&lt;/code&gt; (generator and function respectively) to craft genetators and functions that produce lists of that are known to meet certain criteria, for use in property tests. The generators are not random (as I originally thought).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.&amp;gt; view base.test.v1.nat

  base.test.v1.nat : '{Gen} Nat
  base.test.v1.nat = '(Gen.sample Weighted.nats)

.&amp;gt; view base.test.v1.list

  base.test.v1.list : '{Gen} a -&amp;gt; '{Gen} [a]
  base.test.v1.list g =
    'let
      size = !nat
      List.map (_ -&amp;gt; !g) (range 0 size)

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Gen&lt;/code&gt; ability is handled by the &lt;code&gt;Unison&lt;/code&gt; test runtime. The how exactly is beyond our scope at this time. If you are not fully familiar with abilities, they are covered in the &lt;a href="https://www.unisonweb.org/docs/language-reference#abilities-and-ability-handlers"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  What is the test-predicate function?
&lt;/h5&gt;

&lt;p&gt;The predicate functionchecks if after compression an output-list contains less elements than the input-list. To make the tests a bit more readable the compression is hidden inside the predicate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;should_compress: [a] -&amp;gt; Boolean
should_compress as = (size . compress) as &amp;lt; size as

should_not_compress: [a] -&amp;gt; Boolean
should_not_compress = not . should_compress
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h6&gt;
  
  
  Compressible generators
&lt;/h6&gt;

&lt;p&gt;To benefit from compositionality begin by coding a generator that produces a minimum compressible list (the content of which could be randomised). This generator can then be peppered on to other lists to make any otherwise non compressible list always compressible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;base.test.v1.min_compressible : '{Gen} a -&amp;gt; '{Gen} [a]
base.test.v1.min_compressible g =
  'let
    x = !g
    [x, x]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;min_compressible&lt;/code&gt; gets passed an argument &lt;code&gt;g&lt;/code&gt; that is a delayed generator of type &lt;code&gt;a&lt;/code&gt;. The generator is &lt;code&gt;forced&lt;/code&gt; to produce a value with &lt;code&gt;!g&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;base.test.v1.compressible : '{Gen} a -&amp;gt; '{Gen} [a]
base.test.v1.compressible g =
  'let
    !(min_compressible g) ++ !(list g)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Syntactically, same as above, &lt;code&gt;!(min_compressible g)&lt;/code&gt; forces &lt;code&gt;min_compressible&lt;/code&gt; to return a minimum compressible list, the content of which is produced by the generator &lt;code&gt;g&lt;/code&gt;, and &lt;code&gt;!(list g)&lt;/code&gt; does the same, except the list produced by &lt;code&gt;!(list g)&lt;/code&gt; is not structured. &lt;/p&gt;

&lt;h6&gt;
  
  
  Non compressible generators
&lt;/h6&gt;

&lt;p&gt;Having a second look at the &lt;code&gt;base.test.v1.list&lt;/code&gt; list generator, there is no guarantee that consecutive calls of the &lt;code&gt;g&lt;/code&gt; generator that it reuses for the value of each element, will not yield the same value twice. &lt;/p&gt;

&lt;p&gt;Furthermore &lt;code&gt;g&lt;/code&gt; is passed as an argument so without an in depth understanding of how &lt;code&gt;g&lt;/code&gt; could behaved the &lt;code&gt;list&lt;/code&gt; generator is bound to always produce unexpected results for a whole class of generators like a constant generator that always produces a fixed value.&lt;/p&gt;

&lt;p&gt;Narrowing the scope for &lt;em&gt;natural numbers only&lt;/em&gt;, here is one way to produce a non compressible list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;base.test.v1.non_compressible : '{Gen} [Nat]
base.test.v1.non_compressible =
  'let
    start = !nat
    size  = !nat
    List.map (i -&amp;gt; start + i) (range 0 size)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The list begins with a natural number and all numbers after it are sequenced after incrementing so there can be no consecutive duplicates. But, there is no guarantee that consecutive calls of this generator will not end up producing lists that when concatenated are compressible, for example &lt;code&gt;[1, 2, 3]&lt;/code&gt; and &lt;code&gt;[3]&lt;/code&gt;. To avoid this we would need to code a generator that produces two lists at the same time, to ensure their content cannot be compressed when appended (beyond the scope of this blog).&lt;/p&gt;

&lt;h5&gt;
  
  
  Let's write some properties then!
&lt;/h5&gt;

&lt;h6&gt;
  
  
  The minimum non compressible list is the empty list
&lt;/h6&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test&amp;gt; tests.compress.emptyIsNotCompressible = 
  go _ = expect (should_not_compress [])
  runs 1 go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In a language where there would be a need to import a unit test library and a separate property test library, one might be tempted to code a simple unit test as a property test of a single run, to save the time and energy of dealing with multiple test libraries. In this instance and at this point in time in the evolution of Unison: it does not really matter. The test result is cached regardless.&lt;/p&gt;

&lt;h6&gt;
  
  
  Every list of a single element is non compressible
&lt;/h6&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test&amp;gt; tests.compress.singleElement = 
  go _ = expect (should_not_compress [!nat])
  runs 1 go       
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h6&gt;
  
  
  Every non compressible list can be sequentially deconstructed to non compressible lists
&lt;/h6&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;recurse: ([a] -&amp;gt; Boolean) -&amp;gt; [a] -&amp;gt; Boolean
recurse pred as = 
  pred as &amp;amp;&amp;amp; case (as, as) of 
    (_ +: t, i :+ _) -&amp;gt; recurse pred t &amp;amp;&amp;amp; recurse pred i
    ([], []) -&amp;gt; pred []

test&amp;gt; tests.compress.decomposeU = 
  go _ = l = !(non_compressible)
         expect (recurse should_not_compress l)
  runs 100 go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h6&gt;
  
  
  A non compressible list appended to a non compressible list is compressible under some circumstances
&lt;/h6&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test&amp;gt; tests.compress.uAppendU = 
  go _ = a = !(non_compressible)
         b = !(non_compressible)
         lambda = case (a, b) of
           (_ :+ l, h +: _) -&amp;gt; 
             if h == l then should_compress else should_not_compress
            _ -&amp;gt; should_not_compress
         expect (should_not_compress a 
           &amp;amp;&amp;amp; should_not_compress b &amp;amp;&amp;amp; lambda (a ++ b) )
  runs 100 go       
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h6&gt;
  
  
  Every non empty minimum compressible list can be compressed
&lt;/h6&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test&amp;gt; tests.compress.minimumCompressible = 
  go _ = expect (should_compress !(min_compressible nat))
  runs 100 go       
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h6&gt;
  
  
  Every compressible list appended to a non compressible list results in a compressible list
&lt;/h6&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test&amp;gt; tests.compress.cAppendU = 
  go _ = a = !(min_compressible nat)
         b = !non_compressible
         expect (should_compress a &amp;amp;&amp;amp; should_not_compress b &amp;amp;&amp;amp; should_compress (a ++ b))
  runs 100 go       

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h6&gt;
  
  
  Every non compressible list appended to a compressible list results in a compressible list
&lt;/h6&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test&amp;gt; tests.compress.uAppendC = 
  go _ = a = !non_compressible
         b = !(min_compressible nat)
         expect (should_compress (a ++ b))
  runs 100 go       

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h6&gt;
  
  
  Every compressible list appended to a compressible list results in a compressible list
&lt;/h6&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test&amp;gt; tests.compress.cAppendC = 
  go _ = a = !(min_compressible nat)
         b = !(min_compressible nat)
         expect (should_compress (a ++ b))
  runs 100 go       
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h6&gt;
  
  
  Every compressible list extended by an element is still compressible
&lt;/h6&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test&amp;gt; tests.compress.extendC = 
  go _ = a = !(compressible nat)
         b = !nat
         expect (should_compress a &amp;amp;&amp;amp; should_compress (a ++ [b]))
  runs 100 go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  Closing note
&lt;/h5&gt;

&lt;p&gt;I hope I have managed to communicate in this post just how easy and pleasant it is to work with &lt;code&gt;Unison&lt;/code&gt; when it comes to property based testing. &lt;/p&gt;

</description>
      <category>unison</category>
      <category>testing</category>
      <category>functional</category>
    </item>
    <item>
      <title>Eliminate consecutive duplicates</title>
      <dc:creator>Pete Tsamouris</dc:creator>
      <pubDate>Sat, 11 Jan 2020 18:10:00 +0000</pubDate>
      <link>https://forem.com/petets/eliminate-consecutive-duplicates-57hi</link>
      <guid>https://forem.com/petets/eliminate-consecutive-duplicates-57hi</guid>
      <description>&lt;h4&gt;
  
  
  Disclaimer
&lt;/h4&gt;

&lt;p&gt;As per the previous posts in this series, in the process of helping out the community &lt;code&gt;alphatesting&lt;/code&gt; the &lt;a href="https://www.unisonweb.org/"&gt;&lt;code&gt;Unison&lt;/code&gt;&lt;/a&gt; programming language, I am solving the &lt;a href="https://wiki.haskell.org/H-99:_Ninety-Nine_Haskell_Problems"&gt;&lt;code&gt;99 Haskell problems&lt;/code&gt;&lt;/a&gt; in &lt;code&gt;Unison&lt;/code&gt; and making notes, tailored for a beginner-friendly audience.&lt;/p&gt;

&lt;p&gt;One of the points of the &lt;code&gt;99 exercises&lt;/code&gt; is to try alternative implementations. I will go out of my way (within reason) and explore such alternatives even if a faste, more obvious or easier approach is readily available.&lt;/p&gt;

&lt;p&gt;Understanding of some concepts of functional programming might be required and the intention of this series is to be tailored to a beginner-level audience. For all concepts mentioned in the post I have made the effort to embed relevant hyperlinks. In the event you encounter something you don't fully understand, but does come with a hyperlink-hint feel free to either read to the end then search, or why not get a quick glimpse of the term before you proceed.&lt;/p&gt;

&lt;h4&gt;
  
  
  Exercise 8: Eliminate consecutive duplicates of list elements.
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Can I play too?
&lt;/h5&gt;

&lt;p&gt;To follow along you will need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Unison codebase manager &lt;a href="https://github.com/unisonweb/unison/releases"&gt;&lt;code&gt;ucm&lt;/code&gt;&lt;/a&gt;. Optionally in the &lt;code&gt;$PATH&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A new project created with &lt;code&gt;ucm -codebase path init&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ucm&lt;/code&gt; running your project  under &lt;code&gt;codebase&lt;/code&gt; by means of: &lt;code&gt;ucm -codebase path&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;standard library&lt;/code&gt; (called &lt;code&gt;base&lt;/code&gt;), cloned from inside &lt;code&gt;ucm&lt;/code&gt;: &lt;code&gt;pull https://github.com/unisonweb/base .base&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;An editor of your choice to open &lt;code&gt;scratch.u&lt;/code&gt; under &lt;code&gt;codebase&lt;/code&gt;: &lt;code&gt;ucm&lt;/code&gt; will tell you the folder in which it will pick up any changes to the &lt;a href="https://www.unisonweb.org/docs/tour#unisons-interactive-scratch-files"&gt;&lt;code&gt;scratch file&lt;/code&gt;&lt;/a&gt;, and provide output as necessary.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  So how do we know this thing will work?
&lt;/h5&gt;

&lt;p&gt;Why don't we write some tests first. The function we are trying to write will be called &lt;code&gt;compress&lt;/code&gt; by convention and will reduce a list of elements to a list of maybe less elements. It can directly be placed in the &lt;code&gt;base.List&lt;/code&gt; &lt;a href="https://www.unisonweb.org/docs/language-reference/#namespace-qualified-identifiers"&gt;&lt;code&gt;namespace&lt;/code&gt;&lt;/a&gt;, by adding the path to the namespace before the definition, but that is not necessary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt;

&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nonCompressable1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nonCompressable2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nonCompressable3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compressable1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compressable2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compressable3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;
       &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note: &lt;code&gt;compress&lt;/code&gt; is directly coded into the &lt;code&gt;base.List&lt;/code&gt; namespace above, and all tests point to it by full path. This is equivalent to first using the &lt;code&gt;cd .base.List&lt;/code&gt; command, to move namespace, then coding &lt;code&gt;compress&lt;/code&gt; without a namespace in the declaration and implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  I found and typechecked these definitions in :scratch.u. If
  you do an `add` or `update`, here's how your codebase would
  change:

    ⍟ These new definitions are ok to `add`:

      base.List.compress              : [a] -&amp;gt; [a]
      tests.compress.compressable1    : [Result]
      tests.compress.compressable2    : [Result]
      tests.compress.compressable3    : [Result]
      tests.compress.empty            : [Result]
      tests.compress.example          : [Result]
      tests.compress.nonCompressable1 : [Result]
      tests.compress.nonCompressable2 : [Result]
      tests.compress.nonCompressable3 : [Result]

  Now evaluating any watch expressions (lines starting with
  `&amp;gt;`)... Ctrl+C cancels.

    5 |   run ( expect ( base.List.compress [] == [] ))

    ✅ Passed : Passed 1 tests.

    8 |   run ( expect ( base.List.compress [1] == [1] ))

    🚫 FAILED 

    11 |   run ( expect ( base.List.compress [1, 2] == [1, 2] ))

    🚫 FAILED 

    14 |   run ( expect ( base.List.compress [1, 2, 3] == [1, 2, 3] ))

    🚫 FAILED 

    17 |   run ( expect ( base.List.compress [1, 1, 1, 2, 2, 3] == [1, 2, 3] ))

    🚫 FAILED 

    20 |   run ( expect ( base.List.compress [1, 2, 2, 3] == [1, 2, 3] ))

    🚫 FAILED 

    23 |   run ( expect ( base.List.compress [1, 1] == [1] ))

    🚫 FAILED 

    26 |   run(

    🚫 FAILED 

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The test cases above contain the following inputs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the empty list &lt;code&gt;[]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a non compressible list containing one, two and three elements&lt;/li&gt;
&lt;li&gt;a compressible list beginning with a compressible sequence, and containing a compressible sequence afterwards&lt;/li&gt;
&lt;li&gt;a compressible list beginning with a non compressible sequence, followed by a compressible one&lt;/li&gt;
&lt;li&gt;the &lt;a href="https://wiki.haskell.org/99_questions/1_to_10"&gt;&lt;code&gt;example&lt;/code&gt;&lt;/a&gt; from the problem definition, which on closer  scrutiny and in good humour almost provides more coverage than the previous cases put together.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  So what next?
&lt;/h5&gt;

&lt;p&gt;&lt;code&gt;ucm&lt;/code&gt; agrees with the types and syntax so far so we can &lt;code&gt;add&lt;/code&gt; these definitions, and clear the scratch file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.&amp;gt; add

  ⍟ I've added these definitions:

    base.List.compress              : [a] -&amp;gt; [a]
    tests.compress.compressable1    : [Result]
    tests.compress.compressable2    : [Result]
    tests.compress.compressable3    : [Result]
    tests.compress.empty            : [Result]
    tests.compress.example          : [Result]
    tests.compress.nonCompressable1 : [Result]
    tests.compress.nonCompressable2 : [Result]
    tests.compress.nonCompressable3 : [Result]

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  So can we now implement &lt;code&gt;compress&lt;/code&gt;?
&lt;/h5&gt;

&lt;p&gt;Let's have a first try, while relying on list look-ahead. Previously I would &lt;code&gt;view&lt;/code&gt; a definition on the terminal and then copy-paste that into the scratch file. I will from now on use the &lt;code&gt;edit&lt;/code&gt; command, so that &lt;code&gt;ucm&lt;/code&gt; will do this for me.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
  &lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;then&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+:&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kr"&gt;else&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+:&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+:&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  I found and typechecked these definitions in :scratch.u. If
  you do an `add` or `update`, here's how your codebase would
  change:

    ⍟ These new definitions will replace existing ones of the
      same name and are ok to `update`:

      base.List.compress : [a] -&amp;gt; [a]

  Now evaluating any watch expressions (lines starting with
  `&amp;gt;`)... Ctrl+C cancels.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If the input is the empty list there is nothing to be done and &lt;code&gt;compress&lt;/code&gt; returns the empty list. Alternatively the &lt;code&gt;(x +: (y +: rest))&lt;/code&gt; clause matches on a list of at least two elements, so it can proceed to check these two elements. If they are equal &lt;code&gt;y&lt;/code&gt; is a duplicate of &lt;code&gt;x&lt;/code&gt;, and the next function call will have input of &lt;code&gt;y +: rest&lt;/code&gt; so as not to completely discard the &lt;code&gt;x|y&lt;/code&gt; element. If they are not equal, &lt;code&gt;x&lt;/code&gt; is not discarded and equally &lt;code&gt;y&lt;/code&gt; is not discarded either. Notice that I jumped ahead to a list of &lt;code&gt;two&lt;/code&gt; elements: there is a remaining clause to be matched which I am also adding at this time: &lt;code&gt;[x] -&amp;gt; [x]&lt;/code&gt;. A list containing a single element, just like the empty list, is left intact.&lt;/p&gt;

&lt;p&gt;My first take of the function above, give or take some minor attempts to get the syntax right, was using the pattern &lt;code&gt;(x +: (y +: rest))&lt;/code&gt; to refer to a list of at least two elements. After a comment by &lt;a href="https://github.com/pchiusano"&gt;&lt;code&gt;Paul Chiusano&lt;/code&gt;&lt;/a&gt;, turns out the same can be coded as &lt;code&gt;[x, y] ++ rest&lt;/code&gt;, which saves some bracket noise.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.&amp;gt; update

  ⍟ I've updated to these definitions:

    base.List.compress : [a] -&amp;gt; [a]

  ✅

  No conflicts or edits in progress.

.&amp;gt; test

  ✅  

    New test results:

  ◉ tests.compress.compressable1       : Passed 1 tests.
  ◉ tests.compress.compressable3       : Passed 1 tests.
  ◉ tests.compress.compressable2       : Passed 1 tests.
  ◉ tests.compress.example             : Passed 1 tests.
  ◉ tests.compress.nonCompressable2    : Passed 1 tests.
  ◉ tests.compress.nonCompressable3    : Passed 1 tests.
  ◉ tests.compress.nonCompressable1    : Passed 1 tests.
  ◉ tests.compress.empty               : Passed 1 tests.

  ✅ 8 test(s) passing

  Tip: Use view tests.compress.compressable1 to view the source
       of a test.

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With the function under test updated the tests have "new results". Note however that running the &lt;code&gt;test&lt;/code&gt; command again does not rerun any tests, but shows cached tests results, as long as the function under test has not been updated since the last run.&lt;/p&gt;

&lt;h5&gt;
  
  
  So can we do another one? With less pattern matching?
&lt;/h5&gt;

&lt;p&gt;There might be quite a few alternatives worth exploring and we can begin by looking into an iterative approach using &lt;code&gt;foldl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First a reminder of the signature and implementation of &lt;code&gt;foldl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.&amp;gt; view base.List.foldl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldl&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;𝕖&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;𝕖&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;𝕖&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldl&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;go&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
        &lt;span class="kt"&gt;None&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
        &lt;span class="kt"&gt;Some&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
          &lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="kt"&gt;Nat&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
          &lt;span class="n"&gt;go&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;go&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Going over each element of the list while using an accumulator, if the last element encountered matches the current element then it can be discarded, otherwise this element is appended to the accumulator and will be the basis of comparison in the next iteration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="n"&gt;elem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
    &lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;elem&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="o"&gt;:+&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;elem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;then&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="kr"&gt;else&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;:+&lt;/span&gt; &lt;span class="n"&gt;elem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;foldl&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  I found and typechecked these definitions in :scratch.u. If
  you do an `add` or `update`, here's how your codebase would
  change:

    ⍟ These new definitions will replace existing ones of the
      same name and are ok to `update`:

      base.List.compress : [a] -&amp;gt; [a]

  Now evaluating any watch expressions (lines starting with
  `&amp;gt;`)... Ctrl+C cancels.

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After updating &lt;code&gt;compress&lt;/code&gt;, tests are still passing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.&amp;gt; test

  ✅  

    New test results:

  ◉ tests.compress.example             : Passed 1 tests.
  ◉ tests.compress.empty               : Passed 1 tests.
  ◉ tests.compress.nonCompressable3    : Passed 1 tests.
  ◉ tests.compress.compressable3       : Passed 1 tests.
  ◉ tests.compress.nonCompressable2    : Passed 1 tests.
  ◉ tests.compress.nonCompressable1    : Passed 1 tests.
  ◉ tests.compress.compressable2       : Passed 1 tests.
  ◉ tests.compress.compressable1       : Passed 1 tests.

  ✅ 8 test(s) passing

  Tip: Use view tests.compress.example to view the source of a
       test.

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  Are there more alternative approaches?
&lt;/h5&gt;

&lt;p&gt;Yes there are: one using &lt;code&gt;dropWhile&lt;/code&gt; (not part of the &lt;code&gt;Unison&lt;/code&gt; &lt;code&gt;base&lt;/code&gt; library yet) and one using &lt;code&gt;group&lt;/code&gt; (also not part of &lt;code&gt;base&lt;/code&gt; yet).&lt;/p&gt;

&lt;h5&gt;
  
  
  Care to go ahead regardless?
&lt;/h5&gt;

&lt;h6&gt;
  
  
  Using "dropWhile"
&lt;/h6&gt;

&lt;p&gt;There are probably multiple ways to implement &lt;code&gt;dropWhile&lt;/code&gt; or in other words a function that given a predicate, will keep dropping elements from the head of the list for as long as the predicate holds. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;dropWhile&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The straightforward way is to just implement it as per its definition, without relying on an abstraction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dropWhile&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dropWhile&lt;/span&gt; &lt;span class="n"&gt;pred&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
    &lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;+:&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pred&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="kr"&gt;then&lt;/span&gt; &lt;span class="n"&gt;dropWhile&lt;/span&gt; &lt;span class="n"&gt;pred&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
      &lt;span class="kr"&gt;else&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
  I found and typechecked these definitions in :scratch.u. If
  you do an `add` or `update`, here's how your codebase would
  change:

    ⍟ These new definitions are ok to `add`:

      dropWhile : (a -&amp;gt;{𝕖} Boolean) -&amp;gt;{𝕖} [a] -&amp;gt;{𝕖} [a]

  Now evaluating any watch expressions (lines starting with
  `&amp;gt;`)... Ctrl+C cancels.

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For &lt;code&gt;dropWhile&lt;/code&gt; the predicate is tested and if it is false there are no items to drop. On the other hand if it is true then the head is dropped and &lt;code&gt;dropWhile&lt;/code&gt; recurses into the remaining elements of the tail, using the same mechanism.&lt;/p&gt;

&lt;p&gt;So finally &lt;code&gt;compress&lt;/code&gt; can be implemented in terms of &lt;code&gt;dropWhile&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
    &lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;+:&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; 
      &lt;span class="n"&gt;dropped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dropWhile&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
      &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;+:&lt;/span&gt; &lt;span class="n"&gt;compress&lt;/span&gt; &lt;span class="n"&gt;dropped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  I found and typechecked these definitions in :scratch.u. If
  you do an `add` or `update`, here's how your codebase would
  change:

    ⍟ These new definitions will replace existing ones of the
      same name and are ok to `update`:

      base.List.compress : [a] -&amp;gt; [a]

  Now evaluating any watch expressions (lines starting with
  `&amp;gt;`)... Ctrl+C cancels.

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this version compress firstly acts as a means of breaking the list down to the &lt;code&gt;head +: tail&lt;/code&gt; clause, which then allows the remaining elements of tail to be checked for equality with head and dropped if matching. Once &lt;code&gt;dropWhile&lt;/code&gt; finishes filtering after the current head &lt;code&gt;compress&lt;/code&gt; recurses into the remaining elements of the &lt;code&gt;dropped&lt;/code&gt; intermediate result list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.&amp;gt; update

  ⍟ I've updated to these definitions:

    base.List.compress : [a] -&amp;gt; [a]

  ✅

  No conflicts or edits in progress.

.&amp;gt; test

  ✅  

    New test results:

  ◉ tests.compress.nonCompressable1    : Passed 1 tests.
  ◉ tests.compress.compressable3       : Passed 1 tests.
  ◉ tests.compress.nonCompressable2    : Passed 1 tests.
  ◉ tests.compress.compressable1       : Passed 1 tests.
  ◉ tests.compress.empty               : Passed 1 tests.
  ◉ tests.compress.nonCompressable3    : Passed 1 tests.
  ◉ tests.compress.example             : Passed 1 tests.
  ◉ tests.compress.compressable2       : Passed 1 tests.

  ✅ 8 test(s) passing

  Tip: Use view tests.compress.nonCompressable1 to view the
       source of a test.

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h6&gt;
  
  
  Using "group"
&lt;/h6&gt;

&lt;p&gt;Feel free to experiment with this one which I will describe but not code. Given a function that "groups" same elements into lists, you can run &lt;code&gt;group&lt;/code&gt; on the input and end up with a list of lists of same elements. Collecting the head of each of those lists will give you a neat solution.&lt;/p&gt;

&lt;p&gt;(For those who are a bit more advanced, or curious for more detail, &lt;code&gt;group&lt;/code&gt; could be implemented in terms of &lt;code&gt;groupBy&lt;/code&gt; (spoiler &lt;a href="http://hackage.haskell.org/package/base-4.12.0.0/docs/src/Data.OldList.html#group"&gt;here&lt;/a&gt;), which in turn could be implemented in terms of &lt;code&gt;span&lt;/code&gt; (spoiler &lt;a href="http://hackage.haskell.org/package/base-4.12.0.0/docs/src/GHC.List.html#span"&gt;here&lt;/a&gt;))&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;h5&gt;
  
  
  Note:
&lt;/h5&gt;

&lt;p&gt;A great many thanks to Daniel Skinner for reviewing and commenting the original draft of this post.&lt;/p&gt;

</description>
      <category>unison</category>
      <category>recursion</category>
      <category>list</category>
      <category>alphatesting</category>
    </item>
    <item>
      <title>Make your blogs run!</title>
      <dc:creator>Pete Tsamouris</dc:creator>
      <pubDate>Sun, 05 Jan 2020 18:05:17 +0000</pubDate>
      <link>https://forem.com/petets/make-your-blogs-run-1opb</link>
      <guid>https://forem.com/petets/make-your-blogs-run-1opb</guid>
      <description>&lt;p&gt;&lt;a href="https://www.unisonweb.org/"&gt;&lt;code&gt;Unison&lt;/code&gt;&lt;/a&gt; comes with a convenient way of reproducing user interactions with &lt;code&gt;ucm&lt;/code&gt; for all intents and purposes.&lt;/p&gt;

&lt;p&gt;Originally not aware of transcripts, I started writing the odd &lt;code&gt;Unison&lt;/code&gt; blog the hard way, that is, text in one location, code snippets and output being copy-pasted. The 1980s way of doing things worked out for a lot of people after all. Turns out, if you're working with markdown to begin, graduation to transcripts is not that far off.&lt;/p&gt;

&lt;h5&gt;
  
  
  So what are &lt;code&gt;unison transcripts&lt;/code&gt;?
&lt;/h5&gt;

&lt;p&gt;Transcripts are markdown files with a twist. They mix in blocks of &lt;code&gt;Unison&lt;/code&gt; code, to be typechecked by &lt;code&gt;ucm&lt;/code&gt;, and blocks of commands, to be run by &lt;code&gt;ucm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The input-transcript can be orchestrated in such a way that markdown text as well as &lt;code&gt;unison&lt;/code&gt; and &lt;code&gt;ucm&lt;/code&gt; blocks are interleaved to produce output that is ready for consumption by third parties.&lt;/p&gt;

&lt;h5&gt;
  
  
  What are the pros?
&lt;/h5&gt;

&lt;p&gt;As mentioned, you can formulate your interaction with &lt;code&gt;ucm&lt;/code&gt; in a detailed and documented manner, with comments and explanations to pinpoint specifically for example what the exact requirements are to reproduce a bug or failure.&lt;/p&gt;

&lt;p&gt;No time wasted explaining, just share the transcript, which in effect acts as an integration test. If something is wrong with &lt;code&gt;ucm&lt;/code&gt;, a fix followed by a passing run means the fix holds. (And the unison code base does indeed follow this approach currently).&lt;/p&gt;

&lt;p&gt;Being &lt;code&gt;markdown&lt;/code&gt; files, you can use your editor of choice, and the formatting rules you are (potentially) already familiar with.&lt;/p&gt;

&lt;h5&gt;
  
  
  What are the cons?
&lt;/h5&gt;

&lt;p&gt;Depending on the circumstances, certain aspects of reproducing a whole environment (beginning with a couple of heavy &lt;code&gt;git pulls&lt;/code&gt; for example) might mean that the process can become slow and maybe bloated. &lt;/p&gt;

&lt;p&gt;If your main aim is to share code in general, transcripts cannot replace a code repository.&lt;/p&gt;

&lt;p&gt;Also, each transcript runs in its own sandbox, so cleanup of the sandboxed checkouts will be required afterwards.&lt;/p&gt;

&lt;h5&gt;
  
  
  How does it work in practice?
&lt;/h5&gt;

&lt;p&gt;&lt;code&gt;ucm&lt;/code&gt; outputs the regular markdown of the transcript directly to the output file, until it finds specific &lt;code&gt;fenced&lt;/code&gt; blocks (as per the example that follows). These blocks are translated as &lt;code&gt;ucm&lt;/code&gt; commands (&lt;code&gt;pull&lt;/code&gt; from github, &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt; and all the usual suspects), or &lt;code&gt;unison&lt;/code&gt; code to be typechecked.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ucm&lt;/code&gt; blocks containing commands are issued to a sandboxed &lt;code&gt;ucm&lt;/code&gt; and &lt;code&gt;unison&lt;/code&gt; blocks are typechecked in the same sandbox for correctness. You can emulate the &lt;code&gt;unison&lt;/code&gt; blocks to run in the context of a specific file.&lt;/p&gt;

&lt;h5&gt;
  
  
  Can I play too?
&lt;/h5&gt;

&lt;p&gt;All you need is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Unison codebase manager &lt;a href="https://github.com/unisonweb/unison/releases"&gt;&lt;code&gt;ucm&lt;/code&gt;&lt;/a&gt;. Optionally in the &lt;code&gt;$PATH&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;an editor of your choice edit the transcript in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You need be able to run &lt;code&gt;ucm&lt;/code&gt; and point it to a transcript. Name the transcript &lt;code&gt;example.md&lt;/code&gt;, and when ready, run: &lt;code&gt;ucm transcript example.md&lt;/code&gt;. &lt;/p&gt;

&lt;h5&gt;
  
  
  Where do we start?
&lt;/h5&gt;

&lt;p&gt;A number of examples come with the &lt;a href="https://github.com/unisonweb/unison/tree/master/unison-src/transcripts"&gt;&lt;code&gt;Unison codebase&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://github.com/unisonweb/unison/blob/master/unison-src/transcripts/hello.md"&gt;&lt;code&gt;hello&lt;/code&gt;&lt;/a&gt; being the one I used as a guide.&lt;/p&gt;

&lt;p&gt;For the curious: you might want to look into what happens during the &lt;code&gt;stack exec tests&lt;/code&gt; build step when compiling &lt;code&gt;Unison&lt;/code&gt; from source.&lt;/p&gt;

&lt;h5&gt;
  
  
  What is a "minimum viable transcript"?
&lt;/h5&gt;

&lt;p&gt;Technically, an empty markdown file, although that would not really be of much use to you. So here's an example of content that contains a &lt;code&gt;unison&lt;/code&gt; and a &lt;code&gt;ucm&lt;/code&gt; block.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```unison
str = "hello"
```
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once the above block is typechecked, a &lt;code&gt;ucm&lt;/code&gt; block can issue commands that operate on the previous code block.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```ucm
.&amp;gt; add
.&amp;gt; view str
.&amp;gt; undo
```
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To sum up: a transcript with the above two blocks will create a sandboxed checkout, then typecheck the &lt;code&gt;unison&lt;/code&gt; block, then run the &lt;code&gt;ucm&lt;/code&gt; commands. &lt;/p&gt;

&lt;p&gt;Here is the output of &lt;code&gt;ucm&lt;/code&gt; after processing the transcript successfully.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ucm transcript example.md

  Transcript will be run on a new, empty codebase.

  ⚠️

  Initializing a new codebase in:
  /.../transcript-75f55eaeebee4386

   _____     _             
  |  |  |___|_|___ ___ ___ 
  |  |  |   | |_ -| . |   |
  |_____|_|_|_|___|___|_|_|

  Running the provided transcript file...


⚙️   Processing stanza 2 of 2.
💾  Wrote /.../unison/example.output.md

  🌸

  I've finished running the transcript(s) in this codebase:

    /.../transcript-75f55eaeebee4386

  You can run
  `ucm -codebase /.../transcript-75f55eaeebee4386`
  to do more work with it.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ucm&lt;/code&gt; even provides you with the next command to run, in order to continue interactively, from where the transcript concluded.&lt;/p&gt;

&lt;p&gt;Hope you find transcripts useful!&lt;/p&gt;

&lt;h5&gt;
  
  
  Thanks!
&lt;/h5&gt;

&lt;p&gt;I must at this point thank &lt;a href="https://github.com/aryairani"&gt;&lt;code&gt;Arya Irani&lt;/code&gt;&lt;/a&gt;, for reviewing this post for syntax, grammar and spelling errors.&lt;/p&gt;

</description>
      <category>unison</category>
      <category>alphatest</category>
      <category>markdown</category>
    </item>
    <item>
      <title>Nested list flattening</title>
      <dc:creator>Pete Tsamouris</dc:creator>
      <pubDate>Wed, 01 Jan 2020 16:35:38 +0000</pubDate>
      <link>https://forem.com/petets/nested-list-flattening-1php</link>
      <guid>https://forem.com/petets/nested-list-flattening-1php</guid>
      <description>&lt;h4&gt;
  
  
  Disclaimer
&lt;/h4&gt;

&lt;p&gt;As per the previous post in this series, in the process of helping out the community of people &lt;code&gt;alphatesting&lt;/code&gt; the &lt;a href="https://www.unisonweb.org/"&gt;&lt;code&gt;Unison&lt;/code&gt;&lt;/a&gt; programming language, I am solving the &lt;a href="https://wiki.haskell.org/H-99:_Ninety-Nine_Haskell_Problems"&gt;&lt;code&gt;99 Haskell problems&lt;/code&gt;&lt;/a&gt; in &lt;code&gt;unison&lt;/code&gt;, and making notes, tailored for a beginner-friendly audience.&lt;/p&gt;

&lt;p&gt;One of the points of the &lt;code&gt;99 exercises&lt;/code&gt; is to try alternative implementations: I will go out of my way (within reason) and explore such alternatives, even if a faster, more obvious, or easier approach is readily available.&lt;/p&gt;

&lt;p&gt;Understanding of some concepts of functional programming might be required, and the intention of this series is to be tailored to a beginner-level audience. For all concepts mentioned in the post, I have made the effort to embed relevant hyperlinks, so in the event you encounter something you don't fully understand, feel free to either read to the end then search, or why not get a quick glimpse before you proceed.&lt;/p&gt;

&lt;h4&gt;
  
  
  Exercise 7: Flatten a nested list structure
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Can I play too?
&lt;/h5&gt;

&lt;p&gt;To follow along you will need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Unison codebase manager &lt;a href="https://github.com/unisonweb/unison/releases"&gt;&lt;code&gt;ucm&lt;/code&gt;&lt;/a&gt;. Optionally in the &lt;code&gt;$PATH&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A new project created with &lt;code&gt;ucm -codebase path init&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ucm&lt;/code&gt; running on your target &lt;code&gt;codebase&lt;/code&gt;: &lt;code&gt;ucm -codebase path&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;standard library&lt;/code&gt; (called &lt;code&gt;base&lt;/code&gt;), cloned (from inside &lt;code&gt;ucm&lt;/code&gt;): &lt;code&gt;pull https://github.com/unisonweb/base .base&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;An editor of your choice to open &lt;code&gt;scratch.u&lt;/code&gt;, under the &lt;code&gt;codebase&lt;/code&gt; location: &lt;code&gt;ucm&lt;/code&gt; will pick up any changes to the &lt;a href="https://www.unisonweb.org/docs/tour#unisons-interactive-scratch-files"&gt;&lt;code&gt;scratch file&lt;/code&gt;&lt;/a&gt;, and provide output as necessary.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Wait, &lt;code&gt;nested&lt;/code&gt; lists are a thing?
&lt;/h5&gt;

&lt;p&gt;Unison does support &lt;a href="https://www.unisonweb.org/docs/language-reference/#user-defined-data-types"&gt;&lt;code&gt;user defined types&lt;/code&gt;&lt;/a&gt;, and these will be the focus of this post.&lt;/p&gt;

&lt;p&gt;Consider the following definition, where the nested structure is abstracted behind a single &lt;code&gt;type&lt;/code&gt; signature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;Nested&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Element&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Nested&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Instances of the &lt;code&gt;Nested&lt;/code&gt; type, can contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a single element of type &lt;code&gt;a&lt;/code&gt;, or&lt;/li&gt;
&lt;li&gt;a list of elements of this type, as noted by &lt;code&gt;[Nested a]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Element&lt;/code&gt; and &lt;code&gt;List&lt;/code&gt; are the two &lt;code&gt;constructors&lt;/code&gt; of the &lt;a href="https://en.wikipedia.org/wiki/Algebraic_data_type"&gt;&lt;code&gt;algebraic data type&lt;/code&gt;&lt;/a&gt; &lt;code&gt;Nested&lt;/code&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  And it's as easy as that?
&lt;/h5&gt;

&lt;p&gt;Let's ask &lt;code&gt;ucm&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⍟ These new definitions are ok to `add`:

  type Nested a

  Now evaluating any watch expressions (lines starting with `&amp;gt;`)... Ctrl+C cancels.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To give the semblance of uniformity with the rest of the &lt;code&gt;Unison&lt;/code&gt; data types, I will &lt;code&gt;cd base&lt;/code&gt; before &lt;code&gt;adding&lt;/code&gt; the type to the codebase. You can be reminded of the constructors' signatures by using &lt;code&gt;ls&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.&amp;gt; ls .base.Nested

  1. Element (a -&amp;gt; Nested a)
  2. List    ([Nested a] -&amp;gt; Nested a)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  So what about tests?
&lt;/h5&gt;

&lt;p&gt;We begin by adding the signature of the &lt;code&gt;flatten&lt;/code&gt; method, with a default implementation, to be able to write unit tests. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;nested list&lt;/code&gt; does encode structure in it, so I will try and cover as many types of structure in my tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;flatten&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Nested&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;flatten&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test&amp;gt; tests.flatten.empty = 
  run( expect( flatten ( List []) == []))
test&amp;gt; tests.flatten.elem  = 
  run( expect( flatten ( Element 1) == [1]))
test&amp;gt; tests.flatten.elems =
  run( expect( flatten ( List [Element 1, Element 2]) == [1, 2]))
test&amp;gt; tests.flatten.nestOne =
  run( expect( flatten ( List [ List[Element 1]]) == [1]))
test&amp;gt; tests.flatten.nestedMany =
  run
    (expect
      (   flatten
           (List
             [ Element 1,
               List [List [Element 2, List [Element 3]]],
               Element 4 ])
      == [1, 2, 3, 4]))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here are the scenarios tested:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Empty &lt;code&gt;List&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Single &lt;code&gt;Element&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;List&lt;/code&gt; containing multiple &lt;code&gt;Element&lt;/code&gt; values&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;List&lt;/code&gt; inside a &lt;code&gt;List&lt;/code&gt;, containing an &lt;code&gt;Element&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Element&lt;/code&gt; followed by &lt;code&gt;List&lt;/code&gt;, followed by &lt;code&gt;List&lt;/code&gt; followed by &lt;code&gt;Element&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The above could have been broken down to simpler, more granular test cases, but I find that this is quickly becoming tedious, and does not really offer much additional value to you, the reader. By all means, feel free to experiment with more granular test cases. The last one overlaps in coverage with the third and fourth.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ucm&lt;/code&gt; agrees with the types of the above, and runs the tests, all of which, except the first one, are of course failing (omitted for brevity).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⍟ These new definitions are ok to `add`:

  flatten                  : Nested a -&amp;gt; [a]
  tests.flatten.elem       : [Result]
  tests.flatten.elems      : [Result]
  tests.flatten.empty      : [Result]
  tests.flatten.nestOne    : [Result]
  tests.flatten.nestedMany : [Result]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  Can we now fill in the implementation of &lt;code&gt;flatten&lt;/code&gt;?
&lt;/h5&gt;

&lt;p&gt;Let's by all means. Here's one way to go about it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;flatten&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Nested&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;flatten&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
    &lt;span class="kt"&gt;Element&lt;/span&gt; &lt;span class="n"&gt;el&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;+:&lt;/span&gt; &lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;flatten&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;flatten&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;flatten&lt;/code&gt; encounters an &lt;code&gt;Element&lt;/code&gt;, which only wraps a single &lt;code&gt;el&lt;/code&gt;, all it needs to do is wrap it in a list. If it encounters a &lt;code&gt;List&lt;/code&gt; of any structure of nested values, it breaks it in &lt;code&gt;head +: tail&lt;/code&gt;, and separately &lt;code&gt;recurses&lt;/code&gt; into &lt;code&gt;head&lt;/code&gt; and &lt;code&gt;tail&lt;/code&gt;, concatenating the two calculated results with &lt;code&gt;(++)&lt;/code&gt;. This approach uses &lt;a href="https://en.wikipedia.org/wiki/Recursion_(computer_science)"&gt;&lt;code&gt;simple recursion&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⍟ These new definitions will replace existing ones of the same name and are ok to `update`:

  flatten : Nested a -&amp;gt; [a]

⍟ I've updated to these definitions:

  flatten : .Nested a -&amp;gt; [a]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After the &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;tests&lt;/code&gt; are passing!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ◉ tests.flatten.empty            : Passed 1 tests.
  ◉ tests.flatten.elem             : Passed 1 tests.
  ◉ tests.flatten.nestOne          : Passed 1 tests.
  ◉ tests.flatten.elems            : Passed 1 tests.
  ◉ tests.flatten.nestedMany       : Passed 1 tests.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  Can we &lt;code&gt;generalise&lt;/code&gt; the recursion?
&lt;/h5&gt;

&lt;p&gt;As mentioned in the &lt;a href="https://dev.to/petets/an-adventure-in-alpha-testing-3kfn"&gt;first post&lt;/a&gt; of this series, since the original &lt;code&gt;flatten&lt;/code&gt; is using simple recursion, it can be expressed in terms of &lt;code&gt;foldb&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;flatten&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Nested&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;flatten&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
    &lt;span class="kt"&gt;Element&lt;/span&gt; &lt;span class="n"&gt;el&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;foldb&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As a reminder, here is the &lt;code&gt;foldb&lt;/code&gt; signature (&lt;code&gt;find&lt;/code&gt;/&lt;code&gt;view&lt;/code&gt;), along with the type signatures, as well as orchestration to implement &lt;code&gt;flatten&lt;/code&gt;, layed out one by one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldb&lt;/span&gt;
  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldb&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldb&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Nested&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;                             &lt;span class="n"&gt;flatten&lt;/span&gt;
&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;                           &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;                                           &lt;span class="kt"&gt;[]&lt;/span&gt; 
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Nested&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;                                    &lt;span class="n"&gt;l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;foldb&lt;/code&gt; starts (and ends prematurely if the input is empty), with &lt;code&gt;[]&lt;/code&gt;. Whenever it encounters a component of &lt;code&gt;[Nested a]&lt;/code&gt; (beginning with the &lt;code&gt;head&lt;/code&gt; of &lt;code&gt;l&lt;/code&gt;), it runs the &lt;code&gt;f&lt;/code&gt; function, in this case &lt;code&gt;flatten&lt;/code&gt;. It then concatenates &lt;code&gt;(++)&lt;/code&gt; the output of &lt;code&gt;op a&lt;/code&gt; with the previously accumulated result.&lt;/p&gt;

&lt;p&gt;After an &lt;code&gt;update&lt;/code&gt;, the &lt;code&gt;tests&lt;/code&gt; are still passing.&lt;/p&gt;

&lt;h5&gt;
  
  
  Can the &lt;code&gt;recursion/foldb&lt;/code&gt; be turned into an &lt;code&gt;iteration&lt;/code&gt;?
&lt;/h5&gt;

&lt;p&gt;By relying on a small helper function, the last implementatoin can be expressed in differently formulated manner that avoids &lt;code&gt;foldb&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;First, consider the following signature, where &lt;code&gt;f&lt;/code&gt; can turn a value of &lt;code&gt;a&lt;/code&gt; to a number of values of &lt;code&gt;[b]&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;f&lt;/code&gt; can be passed to a function that, for the sake of uniformity with &lt;code&gt;Haskell&lt;/code&gt;, will be called &lt;code&gt;concatMap&lt;/code&gt;. &lt;code&gt;concatMap&lt;/code&gt; then &lt;code&gt;iterates&lt;/code&gt; over the &lt;code&gt;[a]&lt;/code&gt; and converts each instance to a &lt;code&gt;[b]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I will at this point make a quick detour, and add tests for &lt;code&gt;concatMap&lt;/code&gt;: I rely on it to implement &lt;code&gt;flatten&lt;/code&gt;, so for the sake of thoroughness, it should be functioning as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test&amp;gt; tests.concatMap.empty =
  run (expect (concatMap (a -&amp;gt; [a]) [] == []))
tests.concatMap.idOne =
  run (expect (concatMap (a -&amp;gt; [a]) [1] == [1]))
tests.concatMap.doubleOne =
  run (expect (concatMap (a -&amp;gt; [a, a]) [1] == [1, 1]))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;These tests &lt;code&gt;pass&lt;/code&gt;, and prove that &lt;code&gt;concatMap&lt;/code&gt; indeed only applies &lt;code&gt;f&lt;/code&gt; to each &lt;code&gt;a&lt;/code&gt; in the list, without performing any additional transformations. Feel free to be more thorough, but in the confines of &lt;code&gt;Unison&lt;/code&gt;, the type signatures can be trusted.&lt;/p&gt;

&lt;p&gt;Going back to the task at hand, for our purposes &lt;code&gt;f is flatten&lt;/code&gt;, and &lt;code&gt;a -&amp;gt; [b] is Nested a -&amp;gt; [a]&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;concatMap&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;concatMap&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;foldl&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;

&lt;span class="n"&gt;flatten&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Nested&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;flatten&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
    &lt;span class="kt"&gt;Element&lt;/span&gt; &lt;span class="n"&gt;el&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="n"&gt;ls&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;concatMap&lt;/span&gt; &lt;span class="n"&gt;flatten&lt;/span&gt; &lt;span class="n"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As before, if &lt;code&gt;flatten&lt;/code&gt; encounters an &lt;code&gt;Element&lt;/code&gt;, the &lt;code&gt;a -&amp;gt; [a]&lt;/code&gt; conversion is a "wrap in a list" operation. When it encounters a &lt;code&gt;[Nested a]&lt;/code&gt;, &lt;code&gt;flatten&lt;/code&gt; does not &lt;code&gt;recurse&lt;/code&gt; into itself by calling &lt;em&gt;itself&lt;/em&gt;. Instead it calls &lt;code&gt;concatMap&lt;/code&gt; that uses &lt;code&gt;flatten&lt;/code&gt; as the function to work with. Internally, &lt;code&gt;concatMap&lt;/code&gt; runs &lt;code&gt;foldl&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⍟ These new definitions will replace existing ones of the same name and are ok to `update`:

  flatten : Nested a -&amp;gt; [a]
.&amp;gt; update

⍟ I've updated to these definitions:

  flatten : Nested a -&amp;gt; [a]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With tests passing, that's a wrap!&lt;/p&gt;

</description>
      <category>unison</category>
      <category>recursion</category>
      <category>list</category>
      <category>alphatesting</category>
    </item>
    <item>
      <title>Palindromes</title>
      <dc:creator>Pete Tsamouris</dc:creator>
      <pubDate>Sat, 28 Dec 2019 13:42:45 +0000</pubDate>
      <link>https://forem.com/petets/palindromes-with-unison-5h9o</link>
      <guid>https://forem.com/petets/palindromes-with-unison-5h9o</guid>
      <description>&lt;h4&gt;
  
  
  Disclaimer
&lt;/h4&gt;

&lt;p&gt;As per the &lt;a href="https://dev.to/petets/an-adventure-in-alpha-testing-3kfn"&gt;previous post&lt;/a&gt; in this series, in the process of helping out the community of people &lt;code&gt;alphatesting&lt;/code&gt; the &lt;a href="https://www.unisonweb.org/"&gt;&lt;code&gt;Unison&lt;/code&gt;&lt;/a&gt; programming language, I am solving the &lt;a href="https://wiki.haskell.org/H-99:_Ninety-Nine_Haskell_Problems"&gt;&lt;code&gt;99 Haskell problems&lt;/code&gt;&lt;/a&gt; in &lt;code&gt;unison&lt;/code&gt;, and making notes, tailored for a beginner-friendly audience.&lt;/p&gt;

&lt;p&gt;One of the points of the &lt;code&gt;99 exercises&lt;/code&gt; is to try alternative implementations: I will go out of my way (within reason) and explore such alternatives, even if a faster, more obvious, or easier approach is readily available. Jumping ahead from exercise 1 straight to exercise 6.&lt;/p&gt;

&lt;h4&gt;
  
  
  Exercise 6: Find out whether a list is a palindrome
&lt;/h4&gt;

&lt;p&gt;A definition of a &lt;a href="https://en.wikipedia.org/wiki/Palindrome"&gt;&lt;code&gt;palindrome&lt;/code&gt;&lt;/a&gt; can be found on Wikipedia.&lt;/p&gt;

&lt;h5&gt;
  
  
  Could you follow a "unison workflow" this time?
&lt;/h5&gt;

&lt;p&gt;I previously touched on two &lt;code&gt;ucm&lt;/code&gt; commands: &lt;code&gt;find&lt;/code&gt; and &lt;code&gt;view&lt;/code&gt;, which allow finding functions in the current codebase, and seeing their implementation as stored by the codebase manager.&lt;/p&gt;

&lt;p&gt;In this post I will do showcase the Unison workflow (or my understanding/interpretation of it), by means of the &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt; and potentially other &lt;code&gt;ucm&lt;/code&gt; commands.&lt;/p&gt;

&lt;p&gt;To follow along you will need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Unison codebase manager &lt;a href="https://github.com/unisonweb/unison/releases"&gt;&lt;code&gt;ucm&lt;/code&gt;&lt;/a&gt;. Optionally in the &lt;code&gt;$PATH&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A new project created with &lt;code&gt;ucm -codebase path init&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ucm&lt;/code&gt; running on your target &lt;code&gt;codebase&lt;/code&gt;: &lt;code&gt;ucm -codebase path&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;standard library&lt;/code&gt; (called &lt;code&gt;base&lt;/code&gt;), cloned (from inside &lt;code&gt;ucm&lt;/code&gt;): &lt;code&gt;pull https://github.com/unisonweb/base .base&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;An editor of your choice to open &lt;code&gt;scratch.u&lt;/code&gt;, under the &lt;code&gt;codebase&lt;/code&gt; location: &lt;code&gt;ucm&lt;/code&gt; will pick up any changes to the &lt;a href="https://www.unisonweb.org/docs/tour#unisons-interactive-scratch-files"&gt;&lt;code&gt;scratch file&lt;/code&gt;&lt;/a&gt;, and provide output as necessary.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Why Unison?
&lt;/h5&gt;

&lt;p&gt;One of the selling points of &lt;code&gt;Unison&lt;/code&gt; is that &lt;code&gt;code is content-addressed and immutable&lt;/code&gt;. I would advise taking a close look into &lt;a href="https://www.unisonweb.org/docs/tour#%F0%9F%A7%A0-the-big-technical-idea"&gt;the guide&lt;/a&gt; for a more in-depth explanation.&lt;/p&gt;

&lt;p&gt;In practice and in short: &lt;code&gt;names&lt;/code&gt; do not matter. The compiler keeps track of the &lt;code&gt;abstract syntax tree&lt;/code&gt; representation of the code only, addressing the &lt;code&gt;hashes&lt;/code&gt; and not the &lt;code&gt;names&lt;/code&gt; of other functions and values.&lt;/p&gt;

&lt;p&gt;No more code formatting or renaming vals and functions. To begin.&lt;/p&gt;

&lt;h5&gt;
  
  
  Can you write tests beforehand?
&lt;/h5&gt;

&lt;p&gt;Fan of &lt;a href="https://en.wikipedia.org/wiki/Test-driven_development"&gt;&lt;code&gt;TDD&lt;/code&gt;&lt;/a&gt;? Let's begin by adding a number of lists some being and some not being palindromes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;passing&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="kt"&gt;Nat&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="n"&gt;passing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="kt"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;-- you get the idea&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;failing&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="kt"&gt;Nat&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="n"&gt;failing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt; 
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;-- you also get the idea&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The signature of &lt;code&gt;palindrome&lt;/code&gt; as well as a default implementation are required as a minimum for the code and unit tests to compile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;palindrome&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Boolean&lt;/span&gt;
&lt;span class="n"&gt;palindrome&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Before doing anything else, let's save the scratch file and what &lt;code&gt;ucm&lt;/code&gt; thinks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⍟ These new definitions are ok to `add`:

  failing    : [[Nat]]
  palindrome : [a] -&amp;gt; Boolean
  passing    : [[Nat]]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;No need to see (or care) about these definitions anymore, and the flow is to &lt;code&gt;add&lt;/code&gt; them, clear the scratch file, and proceed. &lt;/p&gt;

&lt;p&gt;Note: tests would normally be added under a dedicated namespace. Code organisation is beyond the scope of this post (for now at least).&lt;/p&gt;

&lt;p&gt;Suggestion: If you'd rather keep code around it can be converted to comments, for example, and to prevent constant &lt;code&gt;views&lt;/code&gt;, comment lines out inline by &lt;code&gt;--&lt;/code&gt; at the beginning of each line, or by adding the comment line: &lt;code&gt;---&lt;/code&gt;. Anything under &lt;code&gt;---&lt;/code&gt; is not taken into account by &lt;code&gt;ucm&lt;/code&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  You still haven't written any tests though...
&lt;/h5&gt;

&lt;p&gt;Indeed I have not. I would rather not have to write each test separately, so let's add a quick helper that applies &lt;code&gt;palindrome&lt;/code&gt; to each member of each list, and aggregates the results to one &lt;code&gt;Boolean&lt;/code&gt; status.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Boolean&lt;/span&gt;
&lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="n"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;foldl&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="n"&gt;nextInput&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="n"&gt;nextInput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt; &lt;span class="n"&gt;inputs&lt;/span&gt;

&lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Boolean&lt;/span&gt;
&lt;span class="n"&gt;failure&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="n"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;foldl&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="n"&gt;nextInput&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="n"&gt;nextInput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;false&lt;/span&gt; &lt;span class="n"&gt;inputs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To the above, after removing the &lt;a href="https://www.unisonweb.org/docs/language-reference/#abilities"&gt;&lt;code&gt;empty ability symbols&lt;/code&gt;&lt;/a&gt;, for clarity, &lt;code&gt;ucm&lt;/code&gt; responds with the following :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⍟ These new definitions are ok to `add`:

  failure : ([a] -&amp;gt; Boolean) -&amp;gt; [[a]] -&amp;gt; Boolean
  success : ([a] -&amp;gt; Boolean) -&amp;gt; [[a]] -&amp;gt; Boolean
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once again the flow is to &lt;code&gt;add&lt;/code&gt; the new definitions, clear the scratch file, and proceed to finally write some test cases! &lt;/p&gt;

&lt;h5&gt;
  
  
  Tests please!
&lt;/h5&gt;

&lt;p&gt;&lt;code&gt;palindrome&lt;/code&gt; is &lt;a href="https://en.wikipedia.org/wiki/Parametric_polymorphism"&gt;parametric&lt;/a&gt; on type &lt;code&gt;a&lt;/code&gt;, so for ease of testing, the tests can use &lt;code&gt;[Nat]&lt;/code&gt;. Writting the tests in the &lt;code&gt;scratch file&lt;/code&gt;  is straightforward and follows &lt;a href="https://www.unisonweb.org/docs/tour#testing-your-code"&gt;the guide&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;
&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;passing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="n"&gt;palindrome&lt;/span&gt; &lt;span class="n"&gt;passing&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;failing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;failure&lt;/span&gt; &lt;span class="n"&gt;palindrome&lt;/span&gt; &lt;span class="n"&gt;failing&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;false&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To the above &lt;code&gt;ucm&lt;/code&gt; responds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⍟ These new definitions are ok to `add`:

  failing.loop : [Result]
  passing.loop : [Result]

  4 | test&amp;gt; passing.loop = run(expect (success palindrome passing == true))

  ✅ Passed : Passed 1 tests. (cached)

  5 | test&amp;gt; failing.loop = run(expect (failure palindrome failing == false))

  🚫 FAILED  (cached)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The tests (as well as the &lt;code&gt;success&lt;/code&gt; and &lt;code&gt;failure&lt;/code&gt; functions) might look attrocious to a more trained eye, but in the spirit of &lt;em&gt;good enough&lt;/em&gt; and not focusing on testing too heavily, now is a good time to &lt;code&gt;add&lt;/code&gt;, clear and proceed with implementing &lt;code&gt;palindrome&lt;/code&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  Implement all the things!
&lt;/h5&gt;

&lt;p&gt;The easiest way to implement &lt;code&gt;palindrome&lt;/code&gt; is to follow the definition of &lt;code&gt;the input reads the same backward as forward&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;palindrome&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;to which &lt;code&gt;ucm&lt;/code&gt; will respond:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⍟ These new definitions will replace existing ones of the same name and are ok to `update`:

   palindrome : [a] -&amp;gt; Boolean
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Before &lt;code&gt;updating&lt;/code&gt; the definition of &lt;code&gt;palindrome&lt;/code&gt;, the second test case is failing, as the original definition is hardcoded:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.&amp;gt; test

  Cached test results (`help testcache` to learn more)

  ◉ passing.loop    : Passed 1 tests.

  ✗ failing.loop   

  🚫 1 test(s) failing, ✅ 1 test(s) passing
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After &lt;code&gt;updating&lt;/code&gt; the implementation, however, it's a whole new picture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.&amp;gt; update

  ⍟ I've updated to these definitions:
    palindrome : [a] -&amp;gt; base.Boolean

  ✅

.&amp;gt; test

  ✅  

    New test results:

  ◉ passing.loop    : Passed 1 tests.
  ◉ failing.loop    : Passed 1 tests.

  ✅ 2 test(s) passing
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Not bad &lt;code&gt;Unison&lt;/code&gt;, not bad at all. However it gets better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.&amp;gt; test

  Cached test results (`help testcache` to learn more)

  ◉ passing.loop    : Passed 1 tests.
  ◉ failing.loop    : Passed 1 tests.

  ✅ 2 test(s) passing
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After updating &lt;code&gt;palindrome&lt;/code&gt;, the very first invocation of the &lt;code&gt;test&lt;/code&gt; command actually runs the tests. With the test definitions being &lt;code&gt;viewable&lt;/code&gt; at any time, subsequent runs will only show cached results. No updates to any code, means no need to run any tests.&lt;/p&gt;

&lt;h5&gt;
  
  
  Could we try another approach?
&lt;/h5&gt;

&lt;p&gt;Let's see what &lt;code&gt;base.List.halve&lt;/code&gt; does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;halve&lt;/span&gt;

  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;halve&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;halve&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="kt"&gt;Nat&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;
      &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The middle index &lt;code&gt;n&lt;/code&gt; is specified as &lt;code&gt;s / 2&lt;/code&gt;. This results in  lists of an even number of elements being split to two halves of equal length. However, lists of an odd number of elements will result in the second half being longer by one element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.&amp;gt; 
    ⧩
    ([1], [2, 1])

    ⧩
    ([1, 2], [3, 2, 1])
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;One approach could be: pick the middle element (&lt;code&gt;2&lt;/code&gt; and &lt;code&gt;3&lt;/code&gt; in the examples above respectively), push it to the end of the first half, then compare the first half, with the &lt;code&gt;reverse&lt;/code&gt; of the second half.&lt;/p&gt;

&lt;h5&gt;
  
  
  But it feels a bit brittle...
&lt;/h5&gt;

&lt;p&gt;Debatable, but agreed. A more robust approach might be to implement a slightly different flavour of &lt;code&gt;halving&lt;/code&gt;, specifically tailored to the needs of &lt;code&gt;palindrome&lt;/code&gt;. A list of even elements will still be split into two lists of equal length, but in the case of an odd number of elements, the two lists will &lt;em&gt;both&lt;/em&gt; contain the middle element.&lt;/p&gt;

&lt;p&gt;This new version of &lt;code&gt;halve&lt;/code&gt;, just like in the &lt;code&gt;base.List&lt;/code&gt; flavour of &lt;code&gt;halve&lt;/code&gt; will still rely on &lt;code&gt;base.List.slice&lt;/code&gt;. The intention is to indeed &lt;code&gt;add&lt;/code&gt; a new function, and not change the &lt;code&gt;halve&lt;/code&gt; implementation by means of &lt;code&gt;updating&lt;/code&gt; it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;

  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Nat&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Nat&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="n"&gt;stopExclusive&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Nat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop&lt;/span&gt; &lt;span class="n"&gt;stopExclusive&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;halve'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;halve'&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;
  &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
  &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kr"&gt;then&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="kr"&gt;else&lt;/span&gt; &lt;span class="n"&gt;halve&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;

&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;halve'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;halve'&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;halve'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;halve'&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])))&lt;/span&gt;
&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;halve'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;two&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;halve'&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])))&lt;/span&gt;
&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;halve'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;three&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;halve'&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])))&lt;/span&gt;
&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;halve'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;four&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;halve'&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;])))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With the new &lt;code&gt;halve'&lt;/code&gt; and relevant tests &lt;code&gt;added&lt;/code&gt;, and tests passing, &lt;code&gt;palindrome&lt;/code&gt; can be reworked. Clearing the scratch file, let's start rewriting &lt;code&gt;palindrome&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;palindrome&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Boolean&lt;/span&gt;
&lt;span class="n"&gt;palindrome&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;halve'&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;
  &lt;span class="n"&gt;at1&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reverse&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;at2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.&amp;gt; 
  I found and typechecked these definitions in ~/unison/scratch.u. If you do an `add` or `update`,
  here's how your codebase would change:

⍟ These new definitions will replace existing ones of the same name and are ok to `update`:

   palindrome : [a] -&amp;gt; Boolean
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Updating the definition and running the tests, the new version does indeed still pass all tests. &lt;/p&gt;

&lt;h5&gt;
  
  
  And what else?
&lt;/h5&gt;

&lt;p&gt;One could also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;zip&lt;/code&gt; the input with its &lt;code&gt;reverse&lt;/code&gt; and &lt;code&gt;foldl&lt;/code&gt; over the tuples, is directly equivalent to the original implementation.&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;base.List.range&lt;/code&gt;, produce a list of all indexes, &lt;code&gt;reverse&lt;/code&gt; it then &lt;code&gt;zip&lt;/code&gt;, to have a list of pairs of elements to be checked for equality. Then access the elements at &lt;code&gt;(0, n), (1, n - 1), .. (n, 0)&lt;/code&gt; and compare them, at the added cost of having to deal with each access returning &lt;code&gt;Optional a&lt;/code&gt;. Probably not the easiest or most testable of approaches.&lt;/li&gt;
&lt;li&gt;Compare the first and last element, without the imperative indexing or direct element access, which can be achieved via pattern matching with the help of an inner function:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;palindrome&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Boolean&lt;/span&gt;
&lt;span class="n"&gt;palindrome&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;go&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;bs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt; &lt;span class="o"&gt;+:&lt;/span&gt; &lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="o"&gt;:+&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;go&lt;/span&gt; &lt;span class="n"&gt;tail&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt; &lt;span class="o"&gt;+:&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;:+&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;
  &lt;span class="n"&gt;go&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As mentioned in the previous post, &lt;code&gt;+:&lt;/code&gt; constructs a list from &lt;code&gt;a head element +: tail list&lt;/code&gt; whereas &lt;code&gt;:+&lt;/code&gt; constructs a list from &lt;code&gt;init list :+ the last element&lt;/code&gt;. The above could be coded without &lt;code&gt;go&lt;/code&gt;, by matching on &lt;code&gt;xs&lt;/code&gt; twice (&lt;code&gt;case (xs, xs) of ...&lt;/code&gt;).&lt;/p&gt;

&lt;h5&gt;
  
  
  Are the tests still passing?
&lt;/h5&gt;

&lt;p&gt;Yes they are, and after the initial upfront investment in time and effort, they made up for it by allowing me to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;have confidence in the continued correctness of &lt;code&gt;palindrome&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;refactor incrementally, multiple times.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  And what about all of those famous palindromes?
&lt;/h5&gt;

&lt;p&gt;Well spotted, all yours:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Text&lt;/span&gt;

&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;palindromes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;greek&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;palindrome&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;toCharList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;"ΝΙΨΟΝΑΝΟΜΗΜΑΤΑΜΗΜΟΝΑΝΟΨΙΝ"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;palindromes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;latin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;palindrome&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;toCharList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;"SATORAREPOTENETOPERAROTAS"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;palindromes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;english1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;palindrome&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;toCharList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;"ablewasiereisawelba"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;palindromes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;english2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;palindrome&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;toCharList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;"amanaplanacanalpanama"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;palindromes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;english3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;palindrome&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;toCharList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;"neveroddoreven"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  Notes!
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;A more thorough explanation of how &lt;code&gt;foldl&lt;/code&gt; works can be found in the &lt;a href="https://dev.to/petets/an-adventure-in-alpha-testing-3kfn"&gt;previous post&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;success&lt;/code&gt;/&lt;code&gt;failure&lt;/code&gt; can be very easily written as a single function: take this as an exercise. 😉&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;unison&lt;/code&gt; also comes with a thorough testing framework which you can locate with &lt;code&gt;find&lt;/code&gt; and &lt;code&gt;view&lt;/code&gt; under &lt;code&gt;base.test.*&lt;/code&gt;. There are probably better ways to aggregate over a number of tests.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;delete&lt;/code&gt; &lt;code&gt;ucm&lt;/code&gt; command can be used to delete no longer needed functions and values from the codebase.&lt;/li&gt;
&lt;li&gt;And as I found out after a very helpful response to my question from &lt;a href="https://github.com/mitchellwrosen"&gt;Mitchell Rosen&lt;/a&gt;, you can &lt;code&gt;delete.namespace target.namespace.here&lt;/code&gt; to get rid of all of the tests above for example.&lt;/li&gt;
&lt;li&gt;If it all goes wrong: &lt;code&gt;undo&lt;/code&gt; is always an option!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>unison</category>
      <category>list</category>
      <category>tdd</category>
      <category>alphatesting</category>
    </item>
    <item>
      <title>Find the last element of a list</title>
      <dc:creator>Pete Tsamouris</dc:creator>
      <pubDate>Wed, 18 Dec 2019 17:37:23 +0000</pubDate>
      <link>https://forem.com/petets/an-adventure-in-alpha-testing-3kfn</link>
      <guid>https://forem.com/petets/an-adventure-in-alpha-testing-3kfn</guid>
      <description>&lt;h4&gt;
  
  
  Disclaimer
&lt;/h4&gt;

&lt;p&gt;I decided to join the community of people currently helping &lt;code&gt;alphatest&lt;/code&gt; the &lt;a href="https://www.unisonweb.org/"&gt;&lt;code&gt;Unison&lt;/code&gt;&lt;/a&gt; programming language. At this point in time, the standard library is actively being worked on. I will embark on solving the &lt;a href="https://wiki.haskell.org/H-99:_Ninety-Nine_Haskell_Problems"&gt;&lt;code&gt;99 Haskell problems&lt;/code&gt;&lt;/a&gt; in &lt;code&gt;unison&lt;/code&gt;, and try and make implementation notes, tailored for a beginner friendly audience. There is little expectation on my part that I will actually make it all the way to 99.&lt;/p&gt;

&lt;p&gt;Some familiarity with concepts like recursion, tail recursion, pattern matching and functional programming might be necessary to follow the code. I have made the effort on my part to embed relevant links, as the post progresses, while at the same time removing &lt;a href="https://www.unisonweb.org/docs/language-reference#abilities-and-ability-handlers"&gt;&lt;code&gt;abilities&lt;/code&gt;&lt;/a&gt; from the type signatures. One of the points of the &lt;code&gt;99 exercises&lt;/code&gt; is to try as many alternative implementations: I will attempt to go out of my way and explore alternatives, even if a faster, more obvious, or easier approach is readily available.&lt;/p&gt;

&lt;h4&gt;
  
  
  Exercise 1: Find the last element of a list
&lt;/h4&gt;

&lt;h5&gt;
  
  
  So what can I work with?
&lt;/h5&gt;

&lt;p&gt;&lt;code&gt;unison&lt;/code&gt; has a unique approach to type declarations: types are identified by their hash, and not their name. As per the snippet &lt;a href="https://www.unisonweb.org/docs/language-reference/#unique-types"&gt;here&lt;/a&gt;, I am using &lt;code&gt;Maybe/Just/Nothing&lt;/code&gt; for the &lt;code&gt;Option a&lt;/code&gt; type.&lt;/p&gt;

&lt;p&gt;As of &lt;code&gt;ucm release 1g&lt;/code&gt; a quick &lt;code&gt;find&lt;/code&gt; on &lt;code&gt;base.List&lt;/code&gt; reveals the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;find&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;
&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.++&lt;/span&gt;        &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop&lt;/span&gt;      &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;    &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;     &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unsnoc&lt;/span&gt;
&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.+:&lt;/span&gt;        &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;     &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;      &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;snoc&lt;/span&gt;      &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;
&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.:+&lt;/span&gt;        &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatMap&lt;/span&gt;   &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;       &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sortBy&lt;/span&gt;    &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;
&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt;        &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldb&lt;/span&gt;     &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;range&lt;/span&gt;     &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt;
&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cons&lt;/span&gt;      &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldl&lt;/span&gt;     &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;   &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uncons&lt;/span&gt;
&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;diagonal&lt;/span&gt;  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;halve&lt;/span&gt;     &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reverse&lt;/span&gt;   &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unfold&lt;/span&gt;
&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;distinct&lt;/span&gt;  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexed&lt;/span&gt;   &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;      &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unsafeAt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Coming from other programming languages that implement &lt;a href="https://en.wikipedia.org/wiki/Cons"&gt;cons lists&lt;/a&gt;, my expectation was that the code would be more or less implemented as a pattern match, involving use of the cons constructor (&lt;code&gt;::&lt;/code&gt;). However, at the time of writing, the language reference around pattern matching on lists was &lt;a href="https://www.unisonweb.org/docs/language-reference/pattern-matching"&gt;not available&lt;/a&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  Simple recursion using &lt;code&gt;uncons&lt;/code&gt;
&lt;/h5&gt;

&lt;p&gt;Let's briefly see what &lt;code&gt;uncons&lt;/code&gt; does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;find&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uncons&lt;/span&gt;
  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uncons&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Given a list of &lt;code&gt;as&lt;/code&gt;, &lt;code&gt;uncons&lt;/code&gt; returns a &lt;code&gt;Maybe (a, [a])&lt;/code&gt; tuple of the head and tail of the list (the tail itself being a list). Using &lt;code&gt;uncons&lt;/code&gt;, the first recursion clause will be &lt;code&gt;Nothing&lt;/code&gt; for an empty list. There is no last element in this case, so the function returns &lt;code&gt;Nothing&lt;/code&gt;. In the case of a head element followed by a tail, the recursion ends when, peeking into the tail, it is found empty, the &lt;code&gt;head&lt;/code&gt; thus being the last element of the list. If the tail does contain more elements, the function recurses into the tail, till a result is found.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="n"&gt;uncons&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
  &lt;span class="kt"&gt;Nothing&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Nothing&lt;/span&gt;
  &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
  &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  But does my function work? (aka unit and property tests)
&lt;/h5&gt;

&lt;p&gt;Using the (very straightforward turns out) &lt;a href="https://www.unisonweb.org/docs/tour#testing-your-code"&gt;testing framework&lt;/a&gt; of &lt;code&gt;unison&lt;/code&gt;, some quick tests prove that the function works as anticipated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;None&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nonEmpty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;go&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;nat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;nat&lt;/span&gt;
         &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;runs&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="n"&gt;go&lt;/span&gt;
&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;None&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="err"&gt;✅&lt;/span&gt; &lt;span class="kt"&gt;Passed&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Passed&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nonEmpty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="err"&gt;✅&lt;/span&gt; &lt;span class="kt"&gt;Passed&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Passed&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;go&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;nat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;✅&lt;/span&gt; &lt;span class="kt"&gt;Passed&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Passed&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  I think there's more in &lt;code&gt;base.List&lt;/code&gt;
&lt;/h5&gt;

&lt;p&gt;Turns out there's another interesting function in base.List, &lt;code&gt;unsnoc&lt;/code&gt;, which I actually at first glance overlooked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;find&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unsnoc&lt;/span&gt;

  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unsnoc&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Given a list of &lt;code&gt;as&lt;/code&gt;, &lt;code&gt;unsnoc&lt;/code&gt; (maybe) breaks the list into: a list containing all but the last element, and the last element. At which point the &lt;code&gt;last&lt;/code&gt; element, needs to just be extracted from the tuple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="n"&gt;at2&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unsnoc&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  How about a more 'formal' or 'generic' way of doing any of this?
&lt;/h5&gt;

&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/Fold_(higher-order_function)"&gt;&lt;code&gt;fold pattern&lt;/code&gt;&lt;/a&gt; is used to generalize over recursion (and tail recursion, more on these to follow).&lt;/p&gt;

&lt;p&gt;Let's briefly see what &lt;code&gt;foldb&lt;/code&gt; does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;find&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldb&lt;/span&gt;
  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldb&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="o"&gt;.&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldb&lt;/span&gt;
  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldb&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldb&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In a (very) generic way, given a function &lt;code&gt;f&lt;/code&gt; to apply, and an operator &lt;code&gt;op&lt;/code&gt;, &lt;code&gt;foldb&lt;/code&gt; will convert a list of &lt;code&gt;a&lt;/code&gt; to a list of &lt;code&gt;b&lt;/code&gt;, using a default term &lt;code&gt;z&lt;/code&gt; as the beginning (and end, if the list is empty). &lt;/p&gt;

&lt;p&gt;Caring only to get the last element of a list, the default &lt;code&gt;z&lt;/code&gt; is &lt;code&gt;Nothing&lt;/code&gt;, the &lt;code&gt;f&lt;/code&gt; provides a way to box elements in a &lt;code&gt;Just&lt;/code&gt; and the &lt;code&gt;op&lt;/code&gt; only cares to keep track of the last element seen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;                  &lt;span class="kt"&gt;Just&lt;/span&gt; 
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;                         &lt;span class="kt"&gt;Nothing&lt;/span&gt; 
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;                             &lt;span class="n"&gt;xs&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt;  

&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;foldb&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;Nothing&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  How about 'tail recursion'?
&lt;/h5&gt;

&lt;p&gt;Quick mention: If a function can be written in terms of &lt;code&gt;recursion&lt;/code&gt;, in certain programming languages, the compiler can optimise the calls to an iteration, if the function is rewritten in a &lt;a href="https://wiki.haskell.org/Tail_recursion"&gt;&lt;code&gt;tail recursive&lt;/code&gt;&lt;/a&gt; manner. &lt;/p&gt;

&lt;p&gt;The intention at this point is not to assess whether the compiler indeed optimises tail recursive calls, but to reimplement the definition of &lt;code&gt;last&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's briefly see what &lt;code&gt;foldl&lt;/code&gt; does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;find&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldl&lt;/span&gt;
  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldl&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="o"&gt;.&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldl&lt;/span&gt;
  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldl&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldl&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In an analogous to &lt;code&gt;foldb&lt;/code&gt; manner, &lt;code&gt;foldl&lt;/code&gt; will require a &lt;code&gt;z&lt;/code&gt; term, as well as an &lt;code&gt;f&lt;/code&gt;, which in this case keeps track of the last element. Notice that boxing in a &lt;code&gt;Just&lt;/code&gt;, happens as the elements are iterated over.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;                  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;                              &lt;span class="kt"&gt;Nothing&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;                            &lt;span class="n"&gt;xs&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt;

&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;foldl&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;Nothing&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  The &lt;code&gt;unison&lt;/code&gt; way!
&lt;/h5&gt;

&lt;p&gt;I reached out to the &lt;code&gt;alphatesting&lt;/code&gt; slack channel for &lt;code&gt;unison&lt;/code&gt;, and &lt;a href="https://github.com/pchiusano"&gt;Paul Chiusano&lt;/a&gt; pointed out that the &lt;code&gt;base.List&lt;/code&gt; data structure in &lt;code&gt;unison&lt;/code&gt; is implemented in terms of a &lt;a href="https://en.wikipedia.org/wiki/Finger_tree"&gt;&lt;code&gt;finger tree&lt;/code&gt;&lt;/a&gt;. There is no need to go over the entire list, since the finger tree provides constant amortized time access to the (first and) last element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;find&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;
  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Nat&lt;/span&gt;
&lt;span class="o"&gt;.&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;find&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt;
  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Nat&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;List.size&lt;/code&gt; returns a &lt;code&gt;Nat&lt;/code&gt; of the size of the list, which then needs to be &lt;code&gt;dropped&lt;/code&gt; by one, since the list is indexed from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;(size - 1)&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  So what would be the "suggested approach"?
&lt;/h5&gt;

&lt;p&gt;&lt;code&gt;unsnoc&lt;/code&gt;, mentioned above, is probably the best balance between a convenient return signature, &lt;code&gt;O(1)&lt;/code&gt; access to either end of the underlying finger tree, simple and straightforward use at the callsite. And for the curious ones, here's a quick peak into what it actually does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unsnoc&lt;/span&gt;
  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unsnoc&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unsnoc&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
      &lt;span class="kt"&gt;None&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;None&lt;/span&gt;
      &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  Final note:
&lt;/h5&gt;

&lt;p&gt;I have avoided a more advanced coding style on purpose. For reference, lambdas parameters to be ignored can be substituded by &lt;code&gt;_&lt;/code&gt;, and function arguments (like &lt;code&gt;xs&lt;/code&gt;) can be dropped on both the left and right hand side of the definition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;foldb&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;Nothing&lt;/span&gt;
&lt;span class="n"&gt;last'&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;foldl&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;Nothing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>unison</category>
      <category>recursion</category>
      <category>list</category>
      <category>alphatesting</category>
    </item>
  </channel>
</rss>
