[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
{car, cdr, cons, listp, nilp, nil,
|
|
|
|
list, pairp, listToString} = require 'cons-lists/lists'
|
|
|
|
|
|
|
|
{Symbol, Comment} = require './reader_types'
|
|
|
|
|
2015-08-26 05:01:21 +00:00
|
|
|
class Normalize
|
|
|
|
normalize: (form) ->
|
|
|
|
return nil if nilp form
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
|
2015-08-26 05:01:21 +00:00
|
|
|
if (pairp form)
|
|
|
|
if (car form) instanceof Symbol and (car form).name in ['vector', 'record']
|
|
|
|
@[(car form).name](cdr form)
|
|
|
|
else
|
|
|
|
@list form
|
|
|
|
else
|
|
|
|
form
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
|
2015-08-26 05:01:21 +00:00
|
|
|
list: (form) ->
|
|
|
|
handle = (form) =>
|
|
|
|
return nil if nilp form
|
|
|
|
if not pairp form
|
|
|
|
return @normalize form
|
|
|
|
cons (@normalize car form), (handle cdr form)
|
|
|
|
handle form
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
|
2015-08-26 05:01:21 +00:00
|
|
|
vector: (form) ->
|
|
|
|
until (nilp form) then p = @normalize(car form); form = cdr form; p
|
|
|
|
|
|
|
|
record: (form) ->
|
|
|
|
o = Object.create(null)
|
|
|
|
until (nilp form)
|
|
|
|
o[(@normalize car form)] = (@normalize car cdr form)
|
|
|
|
form = cdr cdr form
|
|
|
|
null
|
|
|
|
o
|
|
|
|
|
|
|
|
exports.Normalize = Normalize
|
|
|
|
normalize = new Normalize()
|
|
|
|
exports.normalize = -> normalize.normalize.apply(normalize, arguments)
|