Skip to content

Conversation

@devcrafting
Copy link
Contributor

No description provided.

@devcrafting
Copy link
Contributor Author

@blackheaven instead of Twitter discussion...do you really find it more readable?

@blackheaven
Copy link

Yes.

In fact, the idea behind that is due to the non-existence of Algebraic Data Types in lambda calculus.
Each type you write an ADT every sum type is a function and every product type is a function application when 'compiled' to the lambda calculus terms.

If I had to rewrite your code in that mindset:

type PlayerScore =
    | Love
    | Fifteen
    | Thirty

type Player = Player1 | Player2

type Score = NextScore of (Player -> Score)

// val game : Player -> Score
let rec game winner : Score =
    NextScore (fun _ -> game winner)

// val deuce : Score
and deuce : Score =
    NextScore (fun player -> advantage player)
    // NextScore (fun player -> advantage player)

// val advantage : Player -> Score
and advantage p : Score =
    let scoreWhenAdvantage player = function
        | p when p = player -> game p
        | _ -> deuce
    NextScore (scoreWhenAdvantage p)
    // NextScore (fun player -> player |> scoreWhenAdvantage p)

// val forty : Player -> PlayerScore -> Score
and forty p otherPlayerScore : Score =
    let scoreWhenForty (player, otherPlayerScore) = function
        | p when p = player -> game p
        | _ ->
            match otherPlayerScore with
            | Thirty -> deuce
            | Fifteen -> forty player Thirty
            | Love -> forty player Fifteen
    // NextScore (fun player -> player |> scoreWhenForty (p, otherPlayerScore))
    NextScore (scoreWhenForty (p, otherPlayerScore))

// val otherPoints : PlayerScore -> PlayerScore -> Score
and otherPoints p1 p2 : Score =
    let scoreWhenOtherPoints (p1Score, p2Score) = function
        | Player1 ->
            match p1Score with
            | Thirty -> forty Player1 p2Score
            | Fifteen -> otherPoints Thirty p2Score
            | Love -> otherPoints Fifteen p2Score
        | Player2 ->
            match p2Score with
            | Thirty -> forty Player2 p1Score
            | Fifteen -> otherPoints p1Score Thirty
            | Love -> otherPoints p1Score Fifteen
    NextScore (scoreWhenOtherPoints (p1, p2))
    // NextScore (fun player -> player |> scoreWhenOtherPoints (p1, p2))

let scoreAPoint player previousScore =
    match previousScore with
    | NextScore s -> player |> s

deuce
|> scoreAPoint Player1

But it would be messy and tedious (it looks like OOP in certain ways).

Instead of that madness, modern languages allow you to declare the type structure one time and let you add as many 'interpreters' as you want.
That's one of the reason I have the rule one ADT = one pattern matching, you limit the coupling in that way since your interpreter is just a dispatcher.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants