Saturday, December 29, 2018

Reflection on the nature of love

Reflecting on a recent, unexpected Christmas event:

Love isn't a feeling. It's maybe a cross between a decision and a reflex, or maybe it's a decision to create a reflex, to do anything you can to help that person. Love doesn't go away even if the positive feelings that made you decide to commit to it do. Love is permanent, in my experience.

-B.C.

Tuesday, December 18, 2018

Rash Vows

The man who makes a vow makes an appointment with himself at some distant time or place. The danger of it is that himself should not keep the appointment. And in modern times this terror of one's self, of the weakness and mutability of one's self, has perilously increased, and is the real basis of the objection to vows of any kind. A modern man refrains from swearing to count the leaves on every third tree in Holland Walk, not because it is silly to do so (he does many sillier things), but because he has a profound conviction that before he had got to the three hundred and seventy-ninth leaf on the first tree he would be excessively tired of the subject and want to go home to tea...

Let us turn, on the other hand, to the maker of vows. The man who made a vow, however wild, gave a healthy and natural expression to the greatness of a great moment. He vowed, for example, to chain two mountains together, perhaps a symbol of some great relief of love, or aspiration. Short as the moment of his resolve might be, it was, like all great moments, a moment of immortality, and the desire to say of it exegi monumentum aere perennius was the only sentiment that would satisfy his mind. The modern aesthetic man would, of course, easily see the emotional opportunity; he would vow to chain two mountains together. But, then, he would quite as cheerfully vow to chain the earth to the moon. And the withering consciousness that he did not mean what he said, that he was, in truth, saying nothing of any great import, would take from him exactly that sense of daring actuality which is the excitement of a vow.

...It is the nature of love to bind itself, and the institution of marriage merely paid the average man the compliment of taking him at his word. Modern sages offer to the lover, with an ill-favoured grin, the largest liberties and the fullest irresponsibility; but they do not respect him as the old Church respected him; they do not write his oath upon the heavens, as the record of his highest moment. They give him every liberty except the liberty to sell his liberty, which is the only one that he wants.

Source: G.K. Chesterton 

I could not love thee, dear, so much
Loved I not Honor more.

-Max

P.S. I made another rash vow last Friday, December 14, 2018: on my honor, no food shall cross my lips until February 14, 2019, unless I have already reached a satisfactory strength/weight ratio or encounter serious health problems, or unless this vow conflicts with a prior obligation (like taking the sacrament, which obviously takes precedence).

 --

Doubtless some of the arguments developed here will prove oversimplified, or merely false. They are certainly controversial, even among my colleagues in economic history. But far better such error than the usual dreary academic sins, which now seem to define so much writing in the humanities, of willful obfuscation and jargon-laden vacuity. As Darwin himself noted, "false views, if supported by some evidence, do little harm, for every one takes a salutary pleasure in proving their falseness: and when this is done, one path towards error is closed and the road to truth is often at the same time opened."[Darwin, 1998, 629] Thus my hope is that, even if the book is wrong in parts, it will be clearly and productively wrong, leading us toward the light. -Gregory Clark, Preface to Farewell to Alms

Tuesday, December 4, 2018

Great article on roleplaying

I thought this was great: http://darkshire.net/jhkim/rpg/theory/models/blacow.html

-Max

 --

Doubtless some of the arguments developed here will prove oversimplified, or merely false. They are certainly controversial, even among my colleagues in economic history. But far better such error than the usual dreary academic sins, which now seem to define so much writing in the humanities, of willful obfuscation and jargon-laden vacuity. As Darwin himself noted, "false views, if supported by some evidence, do little harm, for every one takes a salutary pleasure in proving their falseness: and when this is done, one path towards error is closed and the road to truth is often at the same time opened."[Darwin, 1998, 629] Thus my hope is that, even if the book is wrong in parts, it will be clearly and productively wrong, leading us toward the light. -Gregory Clark, Preface to Farewell to Alms

Monday, December 3, 2018

Hooray for F#

Hooray!

I think I'm beginning to grok F# computation expressions. I realized recently that an abstraction I've been trying to create--generalized input/output so you can write the same algorithm and execute it both synchronously (a la Console.ReadLine/WriteLine) and in an event loop like React/Elmish--is really just a form of coroutine. Put it together with a packrat parser and you wind up with something like this:

// types for test scenario
type GetNumber = Query of string
type Confirmation = Query of string

type InteractionQuery =
    | Number of GetNumber
    | Confirmation of Confirmation

module Recognizer =
    open Packrat
    let (|Number|_|) = (|Int|_|)
    let (|Bool|_|) = function
        | Word(AnyCase("y" | "yes" | "true" | "t"), ctx) -> Some(true, ctx)
        | Word(AnyCase("n" | "no" | "false" | "f"), ctx) -> Some(false, ctx)
        | _ -> None

module Query =
    open Packrat

    let tryParse recognizer arg =
        match ParseArgs.Init arg |> recognizer with
        | Some(v, End) -> Some v
        | _ -> None

    let confirm txt =
        InteractionQuery.Confirmation(Confirmation.Query txt), (tryParse Recognizer.``|Bool|_|``)
    let getNumber txt =
        InteractionQuery.Number(GetNumber.Query txt), (tryParse Recognizer.``|Number|_|``)

#nowarn "40" // recursive getBurgers is fine
[<Theory>]
[<InlineData(4,true,0,"That will be $8.00 please")>]
[<InlineData(4,true,3,"Thanks! That will be $11.00 please")>]
[<InlineData(3,false,3,"Thanks! That will be $6.00 please")>]
let ``Simulated user interaction``(burgers, getFries, tip, expected) =

    let interaction = InteractionBuilder<string, InteractionQuery>()
    let rec getBurgers : Interactive<_,_,_> =
        interaction {
            let! burger = Query.confirm "Would you like a burger?"
            if burger then
                let! fries = Query.confirm "Would you like fries with that?"
                let price = 1 + (if fries then 1 else 0)
                let! more = getBurgers
                return price + more
            else
                return 0
        }
    let getOrder: Eventual<_, InteractionQuery, _> =
        interaction {
            let! price = getBurgers
            let! tip = Query.confirm "Would you like to leave a tip?"
            if tip then
                let! tip = Query.getNumber "How much?"
                return sprintf "Thanks! That will be $%d.00 please" (tip + price)
            else
                return sprintf "That will be $%d.00 please" price
        }
    let mutable burgerCount = 0
    let question = function
        | Confirmation(Confirmation.Query txt) ->
            if txt.Contains "burger" then
                if burgerCount < burgers then
                    burgerCount <- burgerCount + 1
                    "yes"
                else
                    "no"
            elif txt.Contains "tip" && tip > 0 then
                "yes"
            elif txt.Contains "fries" && getFries then
                "yes"
            else
                "no"
        | Number(GetNumber.Query txt) -> tip.ToString() // must always answer question by typing text
    let resolve =
        let rec resolve monad =
            match monad with
            | Final(v) -> v
            | Intermediate(q,f) as m ->
                let answer = question q
                let m = f answer
                resolve m
        resolve
    Assert.Equal(expected, getOrder |> resolve)

The neat things about this are manyfold:

(1) You can query for numbers (tip amount), yes/no confirmation, or anything else that you want, and it all comes back strongly typed in the context of the algorithm you're executing (getBurgers).

(2) Even though the unit test executes the workflow synchronously via resolve, executing the same logic via React is straightforward: you just take the Intermediate and render the question (q) via React, and dispatch the answer (in string form) back to f. So you can write your business logic without any reference at all to your UI abstractions, and yet it still works in React event loops.

(3) The parser (active patterns in Recognizer) is easy to read and extensible: it looks almost exactly like BNF grammar.

(4) I think it's probably possible to make the parser give you hints about productions that were being matched at the time it ran out of input, so you could give the user hints about what valid inputs they could type next. You could use this in e.g. mobile web development to show autocomplete buttons with the most likely valid responses.

(5) BTW I really like using string format as a canonical form because it's very amenable to pedagogy (teaching the user how they would replicate via text commands the thing you just did on their behalf via the GUI) but you could pick a different canonical form if you wanted to, as long as it's something your event loop knows how to supply.

I'm really happy because I've been working on this problem on and off for probably at least a year, and I finally have a design pattern for user interaction that actually feels _clean_. And in the process I corrected a lot of my misconceptions about computation expressions and what they are good for, and now I have a fairly compelling example to show people of why programming in F# is better/easier/cleaner than C#. :)

~B.C.

 --

Doubtless some of the arguments developed here will prove oversimplified, or merely false. They are certainly controversial, even among my colleagues in economic history. But far better such error than the usual dreary academic sins, which now seem to define so much writing in the humanities, of willful obfuscation and jargon-laden vacuity. As Darwin himself noted, "false views, if supported by some evidence, do little harm, for every one takes a salutary pleasure in proving their falseness: and when this is done, one path towards error is closed and the road to truth is often at the same time opened."[Darwin, 1998, 629] Thus my hope is that, even if the book is wrong in parts, it will be clearly and productively wrong, leading us toward the light. -Gregory Clark, Preface to Farewell to Alms