Table of Contents
- Sum Types in Functional Languages
- Problems with using Tagmeme
- Tagmeme-analyzer: static type-checker and analyzer for tagmeme
- How the analyzer works
Sum Types in Functional Languages
Many functional programming languages, especially statically typed ones like F#, Elm, Haskell etc. have the concept of unions, also known as sum types: these are type definitions used to model values that can be one a of disjoint set of things. For example, you can model a
Shapeto be either a circle, a triangle or a rectangle or you can define a
Colorthat can only be red, green or blue. In a sense, they are like enumerations (enum) in C-style languages but there is a big difference: they can be parameterized with data. A circle has a radius while a rectangle has both height and width. The exact type of data can be encoded in the definition, this is how it looks like in F#:
The different shapes that a shape can be in this example (the circle, the rectangle and the triangle) are called the “union cases” of the
Shape type. Each union case is considered a constructor of
Once you construct a value of a union, you can match against different patterns of the value, for example to determine whether a value is a circle, you match against all the cases the value can be:
One of the best features of modern compilers of functional languages is that they can detect exhaustive pattern matching: whether your code actually takes all possible cases into account and will give you warnings if it doesn’t which is pretty amazing.
As you can see, we define the union “type” of Shape as a list of union cases. Then every case becomes a constructor for
Shape after that we can pattern match against certain values of
To me, this looks just beautiful and it is very similar to what one would write in a language that implements union cases like F# or Elm.
Problems with using Tagmeme
- When forgetting to handle a case (or misspelling the case name)
- When handling a case that wasn’t declared (handling too many cases)
- When handling all cases and still providing a redundant wildcard argument that will never match (see docs)
- When using the work “match” as a union case
- When duplicating union case declarations
- When misspelling union case name in value constructors
Tagmeme-analyzer: static type-checker and analyzer for tagmeme
Because these are known variables where things could go wrong at “compile” time, I asked myself whether it was possible to write a program that checks if we made a silly mistake before actually running the application? Well this was my little experiment for the last week as I delved into the unknown lands of babel parsers to detect where mistakes could occur while providing meaningful alternatives if that is the case: introducing tagmeme-analyzer!
Static code analyzer that checks for exhaustive pattern matching, union case typos and redundant arguments in tagmeme …github.com
Result are declared correctly, but
Duplicates are not, the former has “match” as union case and the latter, well, has duplicate union cases. Here is the consuming code:
In the comments you see what is incorrect, now we need to run
app.js , let us install it first (for now as a global tool)
npm install -g tagmeme-analyzer
then run the analyzer and using the file as an argument, you will get:
As you can see, the analyzer detects all these problems we talked about earlier and if you run it from inside visual studio code, you can navigate to the line where the problem occurs.
How The Analyzer Works
Roughly speaking, the analyzer goes through the following steps
- Parse the code and get an abstract syntax tree (AST) representation of the code
- Find union type declarations from current and imported files
- Traverse the tree and find places where
matchfunction is used with one of the declared union types
- Start matching declared union cases with cases used in the
- Create a list of errors and fuzzy-search for possible alternatives from the declation
- Log the errors to the console
The parser takes in the code that has to be analyzed and returns a tree structure of code with tagged nodes, for example from the code:
Option.Some('value') is converted to
Notice that the code became just data, the analyzer goes through this JSON tree, for example this is a snippet from the analyzer that detects the where the
match function is being used:
this code looks for “call expressions” of which the property is being called as a member (member expression) of an object where the property’s name is “match” and has either two or three arguments and so on and so forth for the rest of the program, see all the code of analyzer.js here.
nyc before the test script. Not to forget how easy debugging was from VS Code.