Andrew Cooke | Contents | Latest | RSS | Previous | Next

C[omp]ute

Welcome to my blog, which was once a mailing list of the same name and is still generated by mail. Please reply via the "comment" links.

Always interested in offers/projects/new ideas. Eclectic experience in fields like: numerical computing; Python web; Java enterprise; functional languages; GPGPU; SQL databases; etc. Based in Santiago, Chile; telecommute worldwide. CV; email.

Personal Projects

Choochoo Training Diary

Last 100 entries

Surprise Paradox; [Books] Good Author List; [Computing] Efficient queries with grouping in Postgres; [Computing] Automatic Wake (Linux); [Computing] AWS CDK Aspects in Go; [Bike] Adidas Gravel Shoes; [Computing, Horror] Biological Chips; [Books] Weird Lit Recs; [Covid] Extended SIR Models; [Art] York-based Printmaker; [Physics] Quantum Transitions are not Instantaneous; [Computing] AI and Drum Machines; [Computing] Probabilities, Stopping Times, Martingales; bpftrace Intro Article; [Computing] Starlab Systems - Linux Laptops; [Computing] Extended Berkeley Packet Filter; [Green] Mainspring Linear Generator; Better Approach; Rummikub Solver; Chilean Poetry; Felicitations - Empowerment Grant; [Bike] Fixing Spyre Brakes (That Need Constant Adjustment); [Computing, Music] Raspberry Pi Media (Audio) Streamer; [Computing] Amazing Hack To Embed DSL In Python; [Bike] Ruta Del Condor (El Alfalfal); [Bike] Estimating Power On Climbs; [Computing] Applying Azure B2C Authentication To Function Apps; [Bike] Gearing On The Back Of An Envelope; [Computing] Okular and Postscript in OpenSuse; There's a fix!; [Computing] Fail2Ban on OpenSuse Leap 15.3 (NFTables); [Cycling, Computing] Power Calculation and Brakes; [Hardware, Computing] Amazing Pockit Computer; Bullying; How I Am - 3 Years Post Accident, 8+ Years With MS; [USA Politics] In America's Uncivil War Republicans Are The Aggressors; [Programming] Selenium and Python; Better Walking Data; [Bike] How Fast Before Walking More Efficient Than Cycling?; [COVID] Coronavirus And Cycling; [Programming] Docker on OpenSuse; Cadence v Speed; [Bike] Gearing For Real Cyclists; [Programming] React plotting - visx; [Programming] React Leaflet; AliExpress Independent Sellers; Applebaum - Twilight of Democracy; [Politics] Back + US Elections; [Programming,Exercise] Simple Timer Script; [News] 2019: The year revolt went global; [Politics] The world's most-surveilled cities; [Bike] Hope Freehub; [Restaurant] Mama Chau's (Chinese, Providencia); [Politics] Brexit Podcast; [Diary] Pneumonia; [Politics] Britain's Reichstag Fire moment; install cairo; [Programming] GCC Sanitizer Flags; [GPU, Programming] Per-Thread Program Counters; My Bike Accident - Looking Back One Year; [Python] Geographic heights are incredibly easy!; [Cooking] Cookie Recipe; Efficient, Simple, Directed Maximisation of Noisy Function; And for argparse; Bash Completion in Python; [Computing] Configuring Github Jekyll Locally; [Maths, Link] The Napkin Project; You can Masquerade in Firewalld; [Bike] Servicing Budget (Spring) Forks; [Crypto] CIA Internet Comms Failure; [Python] Cute Rate Limiting API; [Causality] Judea Pearl Lecture; [Security, Computing] Chinese Hardware Hack Of Supermicro Boards; SQLAlchemy Joined Table Inheritance and Delete Cascade; [Translation] The Club; [Computing] Super Potato Bruh; [Computing] Extending Jupyter; Further HRM Details; [Computing, Bike] Activities in ch2; [Books, Link] Modern Japanese Lit; What ended up there; [Link, Book] Logic Book; Update - Garmin Express / Connect; Garmin Forerunner 35 v 230; [Link, Politics, Internet] Government Trolls; [Link, Politics] Why identity politics benefits the right more than the left; SSH Forwarding; A Specification For Repeating Events; A Fight for the Soul of Science; [Science, Book, Link] Lost In Math; OpenSuse Leap 15 Network Fixes; Update; [Book] Galileo's Middle Finger; [Bike] Chinese Carbon Rims; [Bike] Servicing Shimano XT Front Hub HB-M8010; [Bike] Aliexpress Cycling Tops; [Computing] Change to ssh handling of multiple identities?; [Bike] Endura Hummvee Lite II; [Computing] Marble Based Logic; [Link, Politics] Sanity Check For Nuclear Launch; [Link, Science] Entropy and Life

© 2006-2017 Andrew Cooke (site) / post authors (content).

Erlang's Syntax

From: "andrew cooke" <andrew@...>

Date: Fri, 11 May 2007 09:58:46 -0400 (CLT)

Recently there has been discussion on the Erlang mailing list about "monads".

Monads were popularised by Haskell - they are defined by type constructor
(something that "makes" monads) and two operations: unit and a binding
operation.  And they are used to impose a sequence on a set of operations.
 This is necessary because Haskell is lazy - the order in which functions
are evaluated is not the order in which they are defined in the program -
and so some kind of ordering is needed when doing things that involve
mutable state (for example, asking the user to enter data should come
before reading input!).

OK, but what has this got to do with Erlang?  Very little - Erlang is an
eager language and evaluates functions in a nice, easy-to-understand way. 
So there is no need for ordering.

Monads provide more than ordering - it it turns out that the "monad API"
is quite fundamental, and can be applied to many different scenarios.  So
it provides a unifying concept across lists, optional values, exceptions,
etc.

But, again, the Erlang discussions have nothing to do with this.

In fact, the Erlang discussions are not about the semantics of monads at
all.  The posters are purely concerned with the "syntactic sugar" that
Haskell added to support monads.  This lets you write code in an
"imperative style" - it gives the appearance of mutable values.

So what is really happening?

Partly this is a social phenomenon - it's a lot more acceptable to say "we
need monads" (which are a "cool" concept) than to admit that you want to
program using a style unsuited to the paradigm supported by the language.

But that's not the whole explanation.  This is clear from Haskell, where
the monad syntax is not used for "most" code.  Examples of elegant code,
which are abundant for Haskell, use Haskell's succinct and powerful
"fucntional" syntax.  It, in fact, a "newbie error" to write a program
entirely using the monad-specific "do syntax".

So it's clear it's possible write clear, elegant programs in a functional
style (even when the monad syntax is available).  Why don't people want to
do this in Erlang?

Part of the answer to that question is, again, social.  Erlang is growing
rapidly from a small user base.  So there is a lot of pressure from
incoming programmers, accustomed to procedural programming, who want what
they are accustomed to having.

But part of the answer is also found in Erlang's poor support for common
functional programming idioms.

Take the following line of code, which I wrote earlier today, as an example:

  NonBlankLines =
    filter(compose_1(fun util:not_/1, fun util:is_blank/1), Lines).

This filters a list of lines, discarding those which are not blank.  It
could just have well have been written as:

  NonBlankLines = filter(not is_blank, Lines).

In other words - Erlang *punishes* you when you write code in a functional
style.  It requires you to add a whole pile of pointless noise.  For
example, in the code above:

- compose_1 is necessary because Erlang does not have a syntax for
composing functions.  All I want to do is join two functions together, so
the first processes the output from the second.  This is a basic building
block in functional programming and could be supported by simply writing
the two fucntion names together ("not is_blank", as in the second
version).

- not_ is a utility function necessary because there is no way (that i
could fine) to refer to the inbuilt function "not" directly.  So "not_" is
defined as "not" just because inbuilt functions are, in some odd sense,
broken.

- namespace:name is necessary because even though i have imported these
functions the namespace is *still* necessary when referring to a function
directly.  There's no ambiguity - I could have used "is_blank" alone
(without "util:") if I just wanted to call the function.  This strange
restriction is only necessary when referring to the function's name.

- fun is necessary to flag functions.  Again, this is pointless - when I
call a function I don't need to specify what it is.  Erlang code
religiously follows a naming convention that separates functions and
variables (by case of the first letter) so this doesn't even require any
type analysis.

It's crazy.  The parser is brain-dead lazy.  No wonder people don't "get"
it and keep trying to turn Erlang into C or Java.

Andrew

Two More Problems with Erlang

From: "andrew cooke" <andrew@...>

Date: Fri, 11 May 2007 19:54:11 -0400 (CLT)

Something that doesn't appear in the example above, but is a very common
problem - no support for currying.  This is harder to fix because Erlang
treats functions with the same name but different arities as distinct. 
Also, all parentheses types are already used, so it's hard to add a new
syntax.  However, function application currently alwys looks like
foo(...), so you could use either [...] or {...} and then resolve
ambiguities (with lists and tuples) by context.  Since currying is more
like lists that tuples, I would suggest that foo[1] could be used and
would:
- be an error if more than one arity was defined for a function
- would curry the function by the first argument otherwise.

An alternative would be to use simple juxtaposition, which I was using for
function composition.  Then you'd need a separate operator for composition
- perhaps @ which I don't think is used otherwise.

The second problem is that modules can only define functions.  It is an
error to assign to a variable at the top level of a module.  This has two
consequences - first, it is difficult to export constant values (I tend to
use 0 arity functions for this) and second it is difficult (impossible?)
to define a set of functions with a circular dependency, since there is no
way to "break the loop".  It seems that you have to resort to managing
your own namespace (eg a function that returns a map of functions,
possible because it is created inside a function's scope where bindings to
variables are allowed).

I may be wrong on the second of these - you may need mutability (or
laziness).  I've just come across this problem.  Need to think some more. 
The problem may be that you need higher order functions and these cannot
be "unpacked" into a module's API without more flexibilty at the top level
of modules.

Andrew

Re: Erlang functional syntax

From: "andrew cooke" <andrew@...>

Date: Sat, 12 May 2007 14:48:06 -0400 (CLT)

---------------------------- Original Message ----------------------------
Subject: Re: Erlang functional syntax
From:    "Mike McNally" <m5@...>
Date:    Sat, May 12, 2007 11:06 am
To:      compute-ErlangsSyn0@...
--------------------------------------------------------------------------

I don't disagree completely, but your first example ignores Erlang list
comprehensions:

  NonBlankLines = [L || L <- Lines, not is_blank(L)]

That doesn't seem so bad to me.

--
Mike McNally

You're right + Possible Currying Syntax

From: "andrew cooke" <andrew@...>

Date: Sat, 12 May 2007 15:00:57 -0400 (CLT)

You're right - I keep completely under-using list comprehensions.

However, as far as I know (maybe I simply haven't used them enough)
they're of fairly restricted use - they certainly don't help with
currying.

Incidentally, I think I have a good syntax for currying which would be
backwards compatible with current code.  It involves explicitly specifying
the arity of the function.  In cases where there's no amibuity you can
also use "*".

So, for example,

add(A, B) -> A + B,
Incrementer = add/2(1).

If the function is a variable then it is uniquely specified:

MyAdder = fun add/2.
Incrementer2 = Myadder/*(1).

And the annoying "fun" can be dropped completely, since the trailing
/arity is sufficient to identify functions.  So to increment an array
(maybe I whould be using list comprehensions...)

lists:map(add/2(1), [1,2,3]).

Which is compact, elegant, doesn't break existing code (in particular, I
think common error sin existing code would continue to be errors rather
than silently accepted with a new semantics) and generally "fits in" with
Erlang's style.

Andrew

Partial Evaluation

From: "andrew cooke" <andrew@...>

Date: Thu, 17 May 2007 06:29:40 -0400 (CLT)

http://programming.reddit.com/info/1pw8o/comments/c1pyd5 - has another
solution to this problem, which I also like:

 foo(_, 1, 2),    % fun (A) -> foo(A, 1, 2) end,
 foo(_, 1, _),    % fun (A, B) -> foo(A, 1, B) end,

Then the example might be

 lists:map(add(1, _), [1,2,3]).

(not so keen on the poster's attitude and weird anti-Haskell stance, but
hey...).

They also mention "parse_transform" - it seems Erlang supports some kind
of tree re-writing in the parser, which is pretty cool.  For more info see

http://www.erlang.org/doc/doc-5.5.4/lib/stdlib-1.14.4/doc/html/erl_id_trans.html
http://www.erlang.org/doc/doc-5.5.4/lib/stdlib-1.14.4/doc/html/erl_parse.html

Andrew

Composition via Partial Application

From: "andrew cooke" <andrew@...>

Date: Thu, 17 May 2007 08:04:08 -0400 (CLT)

It seems like partial application either supports, or could be made to
support, composition too:

  NonBlankLines =
    filter(compose_1(fun util:not_/1, fun util:is_blank/1), Lines).

could become

  NonBlankLines = filter(not_(is_blank(_)), Lines).

(There's an unfortunate blurring of underlines there, but I wanted to keep
the same function names as earlier)

Andrew

Comment on this post