Minimal elm program

This is not the shortest Elm hello world program. But it is about as short as I can make an Html.program. Having written it, and read it, it felt somehow profound. Like a haiku.

module Main exposing (..)

import Html exposing (..)


main =
    Html.program
        { init = () ! []
        , update = (\_ a -> a ! [])
        , view = (\_ -> h1 [] [ text "Hello World" ])
        , subscriptions = (\_ -> Sub.none)
        }

Elm support compiled into Universal Ctags

I started this project to make vim-tagbar work with Elm. I use tagbar to get an overview of my source files (especially python); I like how it presents the scope of nested tags. I wanted that overview of my Elm modules too. ctags-elm got me started but exuberant ctags doesn’t let you define scoped tags in config files. Universal Ctags does. So now, after some discussion, the Ctags part of vim-tagbar-ctags-elm is a Universal Ctags optlib. Optlib lets you define a set of command line options in a file, and then generate c source from them so they ca be compiled into ctags executable.

This was always in the plan. Next tagbar itself, maybe?

The Fridge-brilliance of Maybe

I’ve been tinkering with Elm recently. It’s a typed functional programming language that reminds me of the Haskell I wrote during my PhD. And, it’s great fun. I wrote a toy application, and recently upgraded it to 0.17. Along the way I had an insight about the Maybe type which I try and to explain in context.

My generic text input field needs to be able to respond to the Enter and Escape keys by triggering Latch and Reset messages respectively.

My onKeyDown function generates an on-keydown handler attribute that maps Int key codes to messages.

onKeyDown : (Int -> msg) -> Attribute msg
onKeyDown mapping =
    on "keydown" <| Json.map mapping keyCode

This excerpt from my view function shows how I use it; I define enter and escape as constant functions, Latch and Reset are constructors from my Msg type:

view model =
    ...
    div []
	[ input
	    [ type' "text"
	    , highlightStyle
	    , placeholder model.name
	    , value model.input
	    , autofocus True
	    , name model.name
	    , onInput UpdateInput
	    , onKeyDown
		&lt;| keyMsg
		[ ( enter, Latch )
		, ( escape, Reset )
		]
	    ]
	    []
	]

The helper-function keyMsg takes a list of pairs (in lieu of literal dict syntax) from which it builds a dict of key codes and the corresponding messages

keyMsg : List ( Int, Msg ) -> Int -> Msg
keyMsg mapping keycode =
    Dict.fromList mapping
        |> Dict.get keycode
        |> Maybe.withDefault NoOp

Now we get to the interesting part. While writing this I wondered how to return the default value NoOp if the key code isn’t in the dictionary. In python, dict.get(key [, default]) lets you specify the default, so I started looking in the dict module. But it isn’t there. It’s in Maybe.

At which point I saw the Fridge Brilliance of Maybe. Putting the default behaviour inside dict.get means it has to be duplicated in any other data structures that require default behaviour. Making it part of Maybe demonstrates why Maybe so much more than just an abstraction of pointers that might be null. It is the right place to define default-value behaviour.

Edit!

If I bring the names into scope, keyMsg function shortens nicely like this:

keyMsg mapping keycode =
    Dict.fromList mapping |> get keycode |> withDefault NoOp

Whoa! Even more brilliance with the ? operator!

keyMsg mapping keycode =
    Dict.fromList mapping |> get keycode ? NoOp

Get list of worksheets on the command line

Today I need to get a list of worksheets from a very large spreadsheet (~100 worksheets, many thousands of cells on each) quickly from the command line. My ruby script tried to parse the entire workbook and exploded all my RAM. Then I discovered grep -0 which prints matching occurrences only (each on a separate line) which is very useful with regular expression patterns. The “sheet name” entries are in the “workbook.xml” zipped up in the Excel file.

$ unzip -c your-large-spreadsheet.xlsx xl/workbook.xml | grep -o sheet\ name=\"[^\"]*\" | cut -d = -f 2

Getting round the limitations of Excel VBA’s UsedRange function

Turns out that the Excel VBA function UsedRange doesn’t always give the expected results. It gives you the range of cells that have ever been used. If you’ve formatted them, or they used to have values in that you’ve since deleted, you still get those cells. Today I wanted to iterate all cells in a lot of sheets. Some of those sheets had lots of cells in their UsedRange. I hit upon a solution I’ve not seen anywhere else: take the union of constants and formulas in a sheet. This  is quick, because you can use SpecialCells to do the heavy lifting. And you can refine the results to exclude errors using SpecialCells Value argument (the default 23 below selects everything). Here’s the code

Function myUsedRange(ws As Worksheet, Optional lookfor As Long = 23) As Range
    Dim c As Range, f As Range
    On Error Resume Next
    With ws.Range("A1")
        Set c = .SpecialCells(xlCellTypeConstants, lookfor)
        Set f = .SpecialCells(xlCellTypeFormulas, lookfor)
        If c Is Nothing Then Set c = .Cells
        If f Is Nothing Then Set f = .Cells
    End With
    Set myUsedRange = Union(c, f)
End Function

This returns a non-contiguous range containing only the cells you want. This version is a bit lazy and includes [A1] if there are no constants or no formulas matching your search. I didn’t mind because I was using lookfor=2 to search for text which reduced the number of cells by thousands. Hundreds of thousands in some cases. A better version would take a default as a parameter and return it only if neither  constants or formulas gave any results.

pip install rx

I just installed RxPy the Reactive extensions for Python, as you may guess from the title of this article. Well, that was easy. What next? Here’s a delightfully short program which does — ahem — something:

import sys
import rx

rx.Observable.from_(sys.stdin).subscribe(print)

It echoes stdin to stdout. Kinda.

  • There are more newlines than I was expecting — an extra one after each line is echoed
  • The single line is actually an expression returning a Disposable that you can use to unsubscribe. I’m discarding it.
  • I have syntastic installed in Vim and pylint complains of a syntax error when I pass print to subscribe so perhaps I need to configure it to know about python3.

Excel excess: how to remove unwanted styles with VBA

Long story short, I just opened a workbook with 37,000 styles :(. Apparently this is a common problem). Allen Wyatt of ExcelTips suggests deleting non-builtin styles. But I had over 6,000 of those. And some of my user-defined styles are important!

My solution is to remove any style whose name ends with a number, keeping one of each base-name. Cells with deleted styles get “Normal”.

The code uses regular expressions to trim trailing numbers from style names, and uses a dictionary for the set of base names.

Option Explicit

Sub DeduplicateStyles()
  Call DeleteDupStyles(Workbooks("NEW_multi_sector.xlsx"))
End Sub

Sub DeleteDupStyles(wb As Workbook)
  Dim sty As style
  Dim intRet As Integer
  Dim dict As New Scripting.Dictionary
  Dim count As Integer: count = 0

  For Each sty In wb.styles
    Dim n As String: n = trimTrailingNumbers(sty.Name)
    If dict.Exists(n) Then
      ' Debug.Print ("deleting: " & sty.Name)
      On Error Resume Next
      sty.Delete
      If Err.Number <> 0 Then
        Debug.Print ("ERROR deleting: " & sty.Name)
      End If
    Else
      Debug.Print ("keeping: " & sty.Name)
      dict.Add n, 1
    End If

    count = count + 1
    If count Mod 100 = 0 Then
      DoEvents
    End If
  Next sty
End Sub

Function regexp(pattern As String) As regexp
  Dim rx As New regexp
  With rx
    .Global = True
    .MultiLine = False
    .IgnoreCase = False
    .pattern = pattern
  End With
  Set regexp = rx
End Function

Function trimTrailingNumbers(s As String) As String
  trimTrailingNumbers = regexp("( \d+)+$").Replace(s, "")
End Function

Keeping named files in bash

It just took me way too long to solve this, so I’m going to write it up quickly:

The Problem

  • I have a file containing the basenames of spreadsheets that I want to keep in a directory structure. I want to delete all the other spreadsheets.
  • There are levels of nested directories and the files are distributed among them
  • The file names, and the directory names contain spaces (don’t look at me like that, it’s other people’s work on Windoze — at least I’m using bash
  • I’m using bash on Linux, so I have proper find, etc.

A Solution

#!/bin/bash
modelfiles=../files-to-keep.txt

find . -name \*.xls\?  | while read  f
do
    if ! grep -q "${f##*/}" $modelfiles
    then
        rm "$f"
    fi
done

I’m sure there are more efficient ways. Contact me if you have ideas. Meanwhile I’ve got to get back to work so I’m sticking with “it works”.

UPDATE: that didn’t work when I tried to re-run it just now. So switched from grep -v to if ! …

What do chameleons eat?

When this question comes up in a children’s book these days, what do the characters do?

20150627_073158

Zoe (and Beans) rushes inside to Google it.

Which brings me to Mr Christmas and his flying teapot:20150627_073030

All you do is refuel every thousand miles, and you can fly up to three times the speed of sound!

Nic was sceptical.   Google couldn’t give the answer, but Wolfram Alpha did.

At three times the speed of sound, he’s going to have to refuel (with teabags) every 26 minutes and three seconds. For a trip round the world’s circumference that’s nearly eleven hours travel not counting time taken to deliver presents. On top of that he has to stop at least every half hour to brew up. Now add in loo breaks… he’s not going to make it.