Identify Side Effects And Refactor Fearlessly

When we refactor code how can we be confident that we don't break anything?

3 of the most important things that allow us to refactor fearlessly are:

  • Side effect free - or pure - expressions
  • Statically typed expressions
  • Tests

In this article we will solely focus on the aspect of side effects and strictly speaking on how to identify them. Being able to identify side effects in our programs clearly is the precondition for eliminating them.

Why avoid side effects?

Continue reading →

PureScript Case Study And Guide For Newcomers

Have you ever wanted to try out PureScript but were lacking a good way to get started?

If you

  • Have some prior functional programming knowledge - maybe you know Haskell,Elm,F#,or Scala,etc.
  • Want to solve a small task with PureScript
  • And want to get started quickly

This post is for you!

In this post we will walk through setting up and implementing a small exemplary PureScript application from scratch.

Continue reading →

Elm And The Algorithm Of Music

In this article I would like to present a minimal implementation of a music data type and everything that is needed to turn that into audible sound from an Elm application.

We will see how to transcribe an existing composition - an excerpt from Chick Corea's Children's Songs No. 6 - and listen to the result right here,embedded in this article.

From a music data type to performance

My colleague Jonas recently pointed out the presentation Making Algorithmic Music by Donya Quick to me. Donya Quick shows how she uses the Haskell library Euterpea to produce algorithmic music.

It got me really excited about the idea of porting this to Elm and to be able to use this in web applications.

In the following we will see the core data types and algorithms from Euterpea ported to Elm. To focus on the core concepts the implementation is stripped down to the minimum that is required to transcribe and perform an existing polyphonic piece of music (for a single instrument).

Continue reading →

Interactive Command Line Applications In Scala –Well Structured And Purely Functional

This post is about how to implement well structured,and purely functional command line applications in Scala using PureApp.

PureApp originated in an experiment while refactoring out some glue code of an interactive command line application. At the same time it was inspired by the Elm Architecture Pattern,and scalaz's SafeApp,as well as scalm.

To show the really cool things we can do with PureApp,we will implement a self-contained example application from scratch.

This application translates texts from and into different languages. And it provides basic user interactions via the command line.

The complete source code is compiled with tut. Every output (displayed as code comments) is generated by tut.
Continue reading →

How To Use Applicatives For Validation In Scala And Save Much Work

In this post we will see how applicatives can be used for validation in Scala. It is an elegant approach. Especially when compared to an object-oriented way.

Usually when we have operations that can fail,we have them return types like Option or Try. We sequence operations and once there is an error the computation is short circuited and the result is a None or a Failure.

Applicatives allow us to compose independent operations and evaluate each one. Even if an intermediate evaluation fails. This allows us to collect error messages instead of returning only the first error that occurred.

A classic example where this is useful is the validation of user input. We would like to return a list of all invalid inputs rather than aborting the evaluation after the first error.

Scala Cats provides a type that does exactly that. So let's dive into some code and see how it works.

Continue reading →

Parsers in Scala built upon existing abstractions

After some initial struggles,the chapter Functional Parsers from the great book Programming in Haskell by Graham Hutton,where a basic parser library is built from scratch,significantly helped me to finally understand the core ideas of parser combinators and how to apply them to other programming languages other than Haskell as well.

While I recently revisited the material and started to port the examples to Scala I wasn't able to define a proper monad instance for the type Parser[A].

The type Parser[A] alias was defined like this:

type Parser[A] = String =>Option[(A,String)] // defined type alias Parser 

To test the monad laws with discipline I had to provide an instance of Eq[Parser[A]]. Because Parser[A] is a function,equality could only be approximated by showing degrees of function equivalence,which is not a trivial task.

Also the implementation of tailRecM was challenging. (I couldn't figure it out.)

Using existing abstractions

Continue reading →

Strongly Typed Configuration Access With Code Generation

Most config libraries use a stringly typed approach.

Some handle runtime failures due to invalid configuration schemas by leveraging data types like Option or Result to represent missing values or errors. This allows us to handle these failures by either providing default values or by providing decent error messages.

This is a good strategy that we should definitely stick to.

However,the problem with default values is that we might not even notice if the configuration is broken. This could potentially fail in production. In any case an error e.g. due to a misspelled config property will be observable at runtime at the earliest.

Wouldn't it be a great user experience (for us developers) if the compiler told us if the configuration schema is invalid? Even better,imagine we could access the configuration data in a strongly typed way like any other data structure,and with autocompletion.

Moreover,what if we didn't have to write any glue code,not even when the configuration schema changes?

This can be done with the costs of an initial setup that won't take more than probably around 5 minutes.

Continue reading →

Error and state handling with monad transformers in Scala

In this post I will look at a practical example where the combined application (through monad transformers) of the state monad and the either monad can be very useful.

I won't go into much theory,but instead demonstrate the problem and then slowly build it up to resolve it.

You don't have to be completely familiar with all the concepts as the examples will be easy to follow. Here is a very brief overview:

Continue reading →

Use lambdas and combinators to improve your API

If your API overflows with Boolean parameters,this is usually a bad smell.

Consider the following function call for example:

toContactInfoList(csv,true,true) 

When looking at this snippet of code it is not very clear what kind of effect the two Boolean parameters will have exactly. In fact,we would probably be without a clue.

We have to inspect the documentation or at least the parameter names of the function declaration to get a better idea. But still,this doesn't solve all of our problems.

The more Boolean parameters there are,the easier it will be for the caller to mix them up. We have to be very careful.

Moreover,functions with Boolean parameters must have conditional logic like if or case statements inside. With a growing number of conditional statements,the number of possible execution paths will grow exponentially. It will become more difficult to reason about the implementation code.

Can we do better?

Sure we can. Lambdas and combinators come to the rescue and I'm going to show this with a simple example,a refactoring of the function from above.

This post is based on a great article by John A De Goes,Destroy All Ifs — A Perspective from Functional Programming.

I'm going to take John's ideas that he backed up with PureScript examples and present how the same thing can be elegantly achieved in Scala.

Continue reading →

Modelling API Responses With sbt-json –Print Current Bitcoin Price

I'm currently working on an sbt plugin that generates Scala case classes at compile time to model JSON API responses for easy deserialization especially with the Scala play-json library.

The plugin makes it possible to access JSON documents in a statically typed way including auto-completion. It takes a sample JSON document as input (either from a file or a URL) and generates Scala types that can be used to read data with the same structure.

Let's look at a basic example,an app that prints the current Bitcoin price to the console.

Continue reading →

'https://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans+Mono|Open+Sans:400,600,700';.elm-music-play-button,.elm-music-stop-button{margin:2px;}span.n{color:#96C71D;}table.pre,pre.fssnip,pre{line-height:13pt;border:1px solid #d8d8d8;border-collapse:separate;white-space:pre;font:9pt'Droid Sans Mono',consolas,monospace;width:90%;margin:10px 20px 20px;background-color:#212d30;padding:10px;border-radius:5px;color:#d1d1d1;max-width:none;}.shariff{display:block !important;clear:both}.shariff ul{display:flex;flex-direction:row;flex-flow:row wrap;padding:0 !important;margin:0 !important}.shariff li{height:35px;box-sizing:border-box;list-style:none !important;overflow:hidden !important;margin:5px !important;padding:0 !important;text-indent:0 !important;border-left:0 none !important}.shariff a{position:relative;display:block !important;height:35px;padding:0;margin:0;box-sizing:border-box;border:0;text-decoration:none;background-image:none !important;text-align:left;box-shadow:none;cursor:pointer}.shariff .shariff-icon svg{width:32px;height:20px;padding:7px 1px;box-sizing:content-box !important}.shariff-button::before{content:none !important}.shariff .shariff-buttons.theme-round li{width:35px !important;height:35px;border-radius:50%;margin:5px}.shariff .theme-round a{position:relative;height:35px;border-radius:50%}.shariff .theme-round .shariff-icon svg{display:block;margin:auto;padding:8px 1px}.shariff .theme-round .shariff-icon svg path{fill:#fff}.shariff.shariff-align-flex-start ul{justify-content:flex-start;align-items:flex-start}.widget .shariff.shariff-widget-align-flex-start ul{justify-content:flex-start;align-items:flex-start}.widget .shariff li{border:0;font-weight:400}.widget .shariff .theme-default a,.widget .shariff .theme-color a,.widget .shariff .theme-grey a,.widget .shariff .theme-round a{color:#fff;display:block;font-weight:400}@media only screen and (max-width:360px){.shariff .shariff-buttons li{width:35px}.shariff .shariff-buttons .shariff-icon svg{display:block;margin:auto}}@media only screen and (min-width:361px){.shariff .shariff-buttons li{width:125px}}@media screen{@font-face{font-family:'FontAwesome';src:url(/wp-content/themes/editor/inc/fontawesome/fontawesome-webfont.eot);src:url(/wp-content/themes/editor/inc/fontawesome/fontawesome-webfont.eot) format('embedded-opentype'),url(/wp-content/themes/editor/inc/fontawesome/fontawesome-webfont.woff) format('woff'),url(/wp-content/themes/editor/inc/fontawesome/fontawesome-webfont.ttf) format('truetype'),url(/wp-content/themes/editor/inc/fontawesome/fontawesome-webfont.svg) format('svg');font-weight:normal;font-style:normal;}.fa{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg);}100%{-moz-transform:rotate(359deg);}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg);}100%{-webkit-transform:rotate(359deg);}}@-o-keyframes spin{0%{-o-transform:rotate(0deg);}100%{-o-transform:rotate(359deg);}}@keyframes spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg);}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg);}}.fa-times:before{content: "\f00d";}.fa-folder:before{content: "\f07b";}.fa-folder-open:before{content: "\f07c";}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content: "\f0c9";}#simple-social-icons-2 ul li a,#simple-social-icons-2 ul li a:hover,#simple-social-icons-2 ul li a:focus{background-color:#999 !important;border-radius:3px;color:#fff !important;border:0px #fff solid !important;font-size:18px;padding:9px;}}

PureScript Case Study And Guide For Newcomers

Have you ever wanted to try out PureScript but were lacking a good way to get started?

If you

  • Have some prior functional programming knowledge - maybe you know Haskell, Elm, F#, or Scala, etc.
  • Want to solve a small task with PureScript
  • And want to get started quickly

This post is for you!

In this post we will walk through setting up and implementing a small exemplary PureScript application from scratch.

Prerequisites

We assume that we want to run our application from a Node.js environment, maybe an AWS Lambda or some other existing Node.js application.

Project setup

Let's start a new project which we call index-ttl with:

mkdir index-ttl && cd index-ttl && npm init

When prompted for test command enter:

npx spago test

(you can use the defaults for everything else)

Now we will install PureScript, spago a PureScript build tool and purty for code formatting:

npm install --save-dev purescript spago purty

(Note: If the above command fails depending on OS you might have to install the Debian package: libncurses5.)

To initialize a new spago project run

npx spago init

Let's see if our freshly initialized project works by running:

npm test

The output should look similar to this:

root@f883950b5408:/index-ttl# npm test

> index-ttl@1.0.0 test /index-ttl
> npx spago test

[info] Installation complete.
[info] Build succeeded.

You should add some tests.
[info] Tests succeeded.

JavaScript interop

The spago init command has generated some files. The file src/Main.purs contains the main function, the application's entry point.

To call this function from JavaScript we need to bundle the project first.

Given a file index.js in the root folder of the project with the following content:

const Main = require('./Main')

Main.main()

We can bundle and run PureScript project with the command:

npx spago bundle-module --to Main.js && node index.js

Optionally we can add the above command to the scripts property in the package.json file:

"scripts": {
  "test": "npx spago test",
  "start": "npx spago bundle-module --to Main.js && node index.js"
},

Then run the application with npm start.

Code Editor

If you do not have any other preferences I suggest using VS Code with the following extensions:

  • PureScript IDE
    • AFAIK you have to install PureScript globally with npm install -g purescript for this extension to work properly
  • vscode-purty
    • Specify npx purty as the path to the purty executable in the settings. Alternatively you can install purty globally with npm install -g purty

Ready to go

No we have everything in place to start hacking. Maybe you are good on your own now and do not need to read further?

If this is the case my last advice is to refer you to Pursuit, a documentation platform and search engine for PureScript packages (equivalent to Hoogle for Haskell).

In the following sections we will walk through an exemplary implementation of a PureScript application and see e.g. how to

  • Write tests
  • Do dependency injection
  • Handle I/O
  • Make HTTP requests
  • And parse JSON

Implementation

We are going to build an application that removes expired indices from Elasticsearch.

This is an ideal task for an exemplary PureScript application because

  • It involves I/O - in this case calls to the Elasticsearch REST API
  • It involves some processing logic which is not too complex
  • And it is a self-contained, real-world example

Use case

Depending on the kind and load of data that is stored in Elasticsearch it often makes sense to partition the data by time intervals based on index names tagged with a timestamp, e.g. the date. Consider the following indices:

  • index_2020_01_18
  • index_2020_01_19
  • index_2020_01_20
  • index_2020_01_21
  • index_2020_01_22
  • index_2020_01_23

Assume that we establish a 3 day time to live (TTL) and the current date is Jan 23, 2020. This means that all indices dated before Jan 20, 2020 should be removed, namely:

  • index_2020_01_18
  • index_2020_01_19

Given an Elasticsearch hostname and port, the current date, and a TTL in days our app should delete expired indices as described above. The signature of a function could look like this:

deleteExpiredIndices :: Hostname -> Port -> Today -> Ttl -> Aff Unit

But before we get to the implementation of this function we first need to install some additional packages, define some types and write some tests.

Packages

So far the setup has been pretty generic. But now we will install a few npm and PureScript packages specifically for this tutorial:

npm install xhr2
npx spago install aff datetime spec partial refs affjax argonaut-codecs aff-promise formatters

Note that xhr2 is needed for affjax (an AJAX library) if the app is not running in the browser.

spec is needed for testing.

Imports

In the file src/Main.purs we need the following imports:

import Prelude
import Affjax (printError)
import Affjax as AX
import Affjax.ResponseFormat as ResponseFormat
import Control.Promise (fromAff, Promise)
import Data.Argonaut.Core (Json)
import Data.Argonaut.Decode (decodeJson)
import Data.Array (filter, mapMaybe, takeEnd)
import Data.Bifunctor (lmap)
import Data.Date (diff)
import Data.DateTime (Date, canonicalDate, date)
import Data.Either (Either(..), either, note)
import Data.Enum (class BoundedEnum, toEnum)
import Data.Formatter.DateTime (unformatDateTime)
import Data.HTTP.Method (Method(..))
import Data.Int (toNumber, fromString)
import Data.Maybe (Maybe(..))
import Data.String (split, Pattern(..))
import Data.Time.Duration (Days(..))
import Data.Traversable (traverse, sequence)
import Effect (Effect)
import Effect.Aff (Aff)
import Effect.Class.Console (log)

Types, types, types

These types we have already used/seen above:

newtype Hostname
  = Hostname String

newtype Port
  = Port Int

newtype Ttl
  = Ttl Days

newtype Today
  = Today Date

Additionally we need a type that represents an index with a Show instance as well as a representation for an index with a date:

newtype Index
  = Index String

instance showIndex :: Show Index where
  show (Index index) = index

type DatedIndex
  = { name :: Index, date :: Date }

If we wanted to enforce even more type safety we could have put the types into their own modules. By only exposing smart constructors that parse the given arguments we would ensure only valid instances. But this is a bit too much ceremony in this particular situation for my taste. However, the larger the application gets, the more I would tend towards such an approach.

To be able to unit test our application we will pass in the dependencies - in this case the Elasticsearch API calls - as a record of functions:

type ElasticsearchClient
  = { indices :: Aff (Array Index)
    , deleteIndex :: Index -> Aff Unit
    }

Aff represents an asynchronous effect similar to Haskell's IO or Scala's cats.effect.IO or monix.eval.Task.

Now we can change the function signature slightly and also provide a dummy implementation to make it compile:

deleteExpiredIndices :: ElasticsearchClient -> Today -> Ttl -> Aff Unit
deleteExpiredIndices client today ttl = pure unit

Testing

For testing we will use purescript-spec.

We will need the following imports in the file test/Main.purs:

import Prelude
import Data.Array ((:))
import Data.Date.Component (Month(..))
import Data.DateTime (canonicalDate, Date)
import Data.Enum (toEnum)
import Data.Maybe (fromJust)
import Effect (Effect)
import Effect.Aff (Aff, launchAff_)
import Effect.Class (liftEffect)
import Effect.Ref as Ref
import Main (Index(..), Today(..), Ttl(..), deleteExpiredIndices)
import Partial.Unsafe (unsafePartial)
import Test.Spec (describe, it)
import Test.Spec.Assertions (shouldEqual)
import Test.Spec.Reporter.Console (consoleReporter)
import Test.Spec.Runner (runSpec)
import Data.Time.Duration (Days(..))
import Data.Int (toNumber)

Here is a single-example based test for our use case:

main :: Effect Unit
main =
  launchAff_
    $ runSpec [ consoleReporter ] do
        describe "Main" do
          describe "deleteExpiredIndices" do
            it "should delete expired indices" do
              result <- liftEffect $ Ref.new []
              let
                expected =
                  (map show)
                    [ Index "foo_2019_11_15"
                    , Index "foo_2020_01_06"
                    ]
              deleteExpiredIndices
                (client result)
                (Today $ date 2020 January 10)
                (Ttl $ Days $ toNumber 3)
              actual <- liftEffect $ (map show) <$> Ref.read result
              actual shouldEqual expected
  where
  client result =
    { indices:
      pure
        [ Index "foo_2020_01_11"
        , Index "foo_2020_01_10"
        , Index "foo_2020_01_09"
        , Index "foo_2020_01_08"
        , Index "foo_2020_01_07"
        , Index "foo_2020_01_06"
        , Index "foo_2019_11_15"
        , Index "index_without_date"
        ]
    , deleteIndex: \index -> liftEffect $ Ref.modify_ ((:) index) result :: Aff Unit
    }

  date :: Int -> Month -> Int -> Date
  date year month day = unsafePartial fromJust $ (\y d -> canonicalDate y month d) <$> toEnum year <*> toEnum day

Note that we created a test stub for the ElasticsearchClient that returns a hard coded list of indices. And it stores a list of deleted indices in a mutable reference of type Ref (Array Index) which we can use later to make the test assertion.

If we run the test with npm test or npx spago test it fails as expected with the following output:

Main » deleteExpiredIndices
  ✗ should delete expired indices:

  [] ≠ ["foo_2019_11_15","foo_2020_01_06"]

Summary
0/1 test passed

[error] Tests failed: exit code: 1

Let's make the test succeed!

This implementation should suffice:

findExpired :: Today -> Ttl -> Array DatedIndex -> Array DatedIndex
findExpired (Today today) (Ttl ttl) = filter (\indexDate -> (diff today indexDate.date) > ttl)

determineDate :: Index -> Maybe DatedIndex
determineDate (Index name) = { name: Index name, date: _ } <$> dateOrError
  where
  parsed = name # split (Pattern "_") # takeEnd 3

  dateOrError = case parsed of
    [ year, month, day ] ->
      canonicalDate
        <$> strToEnum year
        <*> strToEnum month
        <*> strToEnum day
    _ -> Nothing

  strToEnum ∷ forall e. BoundedEnum e => String -> Maybe e
  strToEnum = fromString >=> toEnum

deleteExpiredIndices :: ElasticsearchClient -> Today -> Ttl -> Aff Unit
deleteExpiredIndices client today ttl = do
  indices <- client.indices
  let
    datedIndices = indices # mapMaybe determineDate

    expired = findExpired today ttl datedIndices
  void $ client.deleteIndex traverse (expired # map _.name)

The function deleteExpiredIndices

  • Calls the indices function from the Elasticsearch client
  • Determines the dates by parsing the index names by calling determineDate
  • Determines which indices are expired by calling findExpired
  • And for each expired index calls deleteIndex from the Elasticsearch client

What is left?

Yes, we need to provide a real Elasticsearch client and integrate everything with our index.js.

If we query indices in JSON format we get result similar to this:

curl 'localhost:9200/_cat/indices?format=json&pretty'
[
  {
    "health" : "yellow",
    "status" : "open",
    "index" : "index_2020_01_22",
    "uuid" : "-gvBWXdPTjudCyVN-oxRKw",
    "pri" : "1",
    "rep" : "1",
    "docs.count" : "0",
    "docs.deleted" : "0",
    "store.size" : "230b",
    "pri.store.size" : "230b"
  },
  {
    "health" : "yellow",
    "status" : "open",
    "index" : "index_2020_01_23",
    "uuid" : "qLWKjqAQR5eubp5RWIn8HA",
    "pri" : "1",
    "rep" : "1",
    "docs.count" : "0",
    "docs.deleted" : "0",
    "store.size" : "230b",
    "pri.store.size" : "230b"
  }
]

The only relevant field of the JSON output is index. So let's create a type for that:

type ElasticsearchIndex
  = { index :: String }

A decoder for this can simply be derived with the help of the purescript-argonaut-codecs library by calling decodeJson.

The HTTP calls to the Elasticsearch API is done with affjax:

elasticsearchClient :: Hostname -> Port -> ElasticsearchClient
elasticsearchClient (Hostname hostname) (Port port) =
  { indices:
    indices
      <#> (map _.body)
      <#> (lmap printError)
      <#> (_ >>= indexFromJson)
      >>= either (\err -> log err $> []) pure
      <#> (map (_.index >>> Index))
  , deleteIndex:
    \(Index index) ->
      delete index >>= either (printError >>> log) (const (log $ "Deleted index: " <> index))
  }
  where
  url = "http://" <> hostname <> ":" <> show port

  indexFromJson :: Json -> Either String (Array ElasticsearchIndex)
  indexFromJson = decodeJson

  indices =
    AX.request
      ( AX.defaultRequest
          { url = url <> "/_cat/indices?format=json"
          , method = Left GET
          , responseFormat = ResponseFormat.json
          }
      )

  delete index =
    AX.request
      ( AX.defaultRequest
          { url = url <> "/" <> index
          , method = Left DELETE
          , responseFormat = ResponseFormat.ignore
          }
      )

In the main function we parse all inputs and call deleteExpiredIndices. The result is transformed to a Promise to provide JavaScript interop.

main :: String -> String -> String -> String -> Effect (Promise Unit)
main datetime ttl hostname port = do
  fromAff $ deleteExpiredIndices
    <$> maybeClient
    <*> dateOrError
    <*> ttlOrError
    # sequence
    >>= either log pure
  where
  dateOrError = unformatDateTime "YYYY-MM-DDTHH:mm:ssZ" datetime # map (date >>> Today)

  ttlOrError = fromString ttl # map (days >>> Ttl) # note "Invalid TTL"

  portOrError = fromString port # map Port # note "Invalid port"

  maybeClient = elasticsearchClient (Hostname hostname) <$> portOrError

This can be called from the index.js like this:

Main.main("2020-01-21T00:00:00Z")("3")("localhost")("9200")()

Finally bundle and run with npm start or npx spago bundle-module --to Main.js && node index.js.

The complete source code from this post can be found on GitHub.

Conclusion

How to get started with a new technology can often best be shown by an example.

This post contains a complete and self-contained example of how to write a PureScript application and how to integrate it into an existing project.

We have covered:

  • Generic project setup with spago
  • JavaScript interop
  • Tests
  • Dependency injection
  • I/O and side effects
  • HTTP requests
  • JSON

Hope this gives you the edge on getting started with PureScript.

I'd love to hear how it works out for you! And I'm happy too about any other feedback.

🙏