lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Scheme syntax vs. other languages [was: Re: Appreciation / Financial


From: David Kastrup
Subject: Re: Scheme syntax vs. other languages [was: Re: Appreciation / Financial support]
Date: Thu, 07 Jun 2012 06:24:02 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1.50 (gnu/linux)

Joseph Rushton Wakeling <address@hidden> writes:

> Scheme (and all other LISP dialects), Haskell and so on have a starkly
> different notational style and set of programming paradigms that make
> them difficult to adapt to from current mainstream programming
> approaches.  That puts a barrier in the way of lots of potential
> contributors.

The principal source of contributors are musicians, not programmers.
C++ is much more mainstream, and will you claim that we have more people
working with the C++ parts of LilyPond than with the Scheme parts?

How many people extend LaTeX writing Pascal code rather than TeX code?
Which if Pascal and TeX is the more mainstream language?  Which is
saner?  That's so far from being even competitive that it isn't funny.

>> Anyway, show the code.  Take a snippet of LilyPond code, pretend that
>> LilyPond's extension language is Python, and show how it should look
>> like under that pretense.
>
> I've no intention of proposing Python as the extension language, but
> I'll do what you suggest with D.
>
> Here's a Scheme function, naturalize-pitch, which was written (not by
> me) to remove double-accidentals and enharmonically rewrite B#, E# and
> Cb, Fb.  It can be found in:
> http://lilypond.org/doc/v2.15/Documentation/notation/changing-multiple-pitches#transpose
>
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> (define (naturalize-pitch p)
>   (let ((o (ly:pitch-octave p))
>         (a (* 4 (ly:pitch-alteration p)))
>         ;; alteration, a, in quarter tone steps,
>         ;; for historical reasons
>         (n (ly:pitch-notename p)))
>     (cond
>      ((and (> a 1) (or (eq? n 6) (eq? n 2)))
>       (set! a (- a 2))
>       (set! n (+ n 1)))
>      ((and (< a -1) (or (eq? n 0) (eq? n 3)))
>       (set! a (+ a 2))
>       (set! n (- n 1))))
>     (cond
>      ((> a 2) (set! a (- a 4)) (set! n (+ n 1)))
>      ((< a -2) (set! a (+ a 4)) (set! n (- n 1))))
>     (if (< n 0) (begin (set! o (- o 1)) (set! n (+ n 7))))
>     (if (> n 6) (begin (set! o (+ o 1)) (set! n (- n 7))))
>     (ly:make-pitch o n (/ a 4))))
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>
>
> Here's the D equivalent.  Note that I've defined a basic object to
> represent a LilyPond pitch, which has the same characteristics as the
> pitch object used by the Scheme code.  It's probably not how a pitch
> object would best be defined but is just there to illustrate.
>
> I've also included a few of D's safety features with assert() commands
> to ensure that the variables have the properties required.
>
> //////////////////////////////////////////////////////////////////
> struct LilyPitch
> {
>     int octave;
>     int notename;

What is an int?  Why do I need these lines?

>     double alteration;

Too bad that alterations are _rationals_, namely exact numbers.  double
arithmetic is not associative.

>     pure this(int o, int n, double a)

What is "pure"?  Can I eat it?

>     in
>     {
>         assert(0 <= n && n <= 6);
>         assert(-1 <= a && a <= 1);
>     }

What's with "in" and the braces?  How do I know that && has lower
precedence than <=?

>     body
>     {
>         octave = o;
>         notename = n;
>         alteration = a;
>     }
> }
>
> pure auto naturalizePitch(LilyPitch p)

What is pure?  What is auto?

> {
>     // Here we mimic what the Scheme function does and define separate
>     // temporary variables to store the octave, note name and alteration.
>     // We could just tweak p.octave, p.notename and p.alteration
>     // directly, but I choose to assume that with a properly defined
>     // LilyPitch we wouldn't have that possibility.
>     auto o = p.octave;
>     auto n = p.notename;
>     auto a = p.alteration;

Why do I need to declare the types of p.octave etc, but not of o, n, a?

>     // First, we disallow anything greater than +1/4-tone on E and B,
>     // and anything less than -1/4-tone on C and F.  In other words,
>     // no E# or B#, no Cb or Fb.
>     if(a > 0.25 && (n == 6 || n == 2))

What are the implications of using an inexact data type?  Shouldn't I be
doing my comparisons with some epsilon added?

>     {
>         a -= 0.5;
>         n += 1;
>     }

What's a "-="?  Why do I need that semicolon before "}"?

>     else if(a < -0.25 && (n == 0 || n == 3))

Who will teach me about the dangling else problem?

>     {
>         a += 0.5;
>         n -= 1;
>     }
>
>     // Once that's dealt with, we disallow any accidental stronger than
>     // a sharp or a flat, on ANY note.
>     if(a > 0.5)

Is "if" a function call?

>     {
>         a -= 1.0;
>         n += 1;
>     }
>     else if(a < -0.5)

should I not rather be indenting the "else if"?

>     {
>         a += 1.0;
>         n -= 1;
>     }
>
>     // Last, we clean up the octave placement.
>     if(n < 0)
>     {
>         o -= 1;
>         n += 7;
>     }
>     else if(n > 6)
>     {
>         o += 1;
>         n -= 7;
>     }
>
>     // Let's check that the note really falls within the
>     // bounds we are looking for ...
>     assert(0 <= n && n <= 6);
>     assert(-0.5 <= a && a <= 0.5);
>     if(n == 2 || n == 6)
>         assert(a < 0.5);
>     if(n == 0 || n == 3)
>         assert(a > -0.5);
>
>     return LilyPitch(o, n, a);
> }
> //////////////////////////////////////////////////////////////////
>
> Now, I don't think the naturalize-pitch Scheme function is necessarily
> the best advertisement for Scheme I've ever seen, but I defy anyone to
> tell me that the D code is not clearer to follow, even without my
> added comments.

For a musician?  Apart from the problems with the inexact numeric type?
And now you just need to recompile and link your LilyPond executable?
And how will you _use_ this function?  Where do you have to declare it?
Do you have to load a dynamic library?

You picked a _Scheme_ function, not a music function.  That does not, I
repeat _not_ at all show how you embed this thing into your LilyPond
code, and we were talking about using D as an _extension_ language of
LilyPond, not about its usefulness as a general purpose programming
function.

So please, try again.  This time picking something that actually
solves a task in LilyPond.

Something like
Documentation/snippets/adding-extra-fingering-with-scheme.ly (which
actually does a ridiculous amount using Scheme rather than #{...#} but
let's just assume that as a given).

Or how would you write something like

applyMusic =
#(define-music-function (parser location func music) (procedure? ly:music?)
   (_i"Apply procedure @var{func} to @var{music}.")
   (func music))

in LilyPond/D?  How would you call it from LilyPond?

In the snippets I see the following (it is actually rather awful code:
one would use music-is-of-type? rather than memq, and of course it does
not do to copy all properties rather than just those supported by
SkipEvent, namely duration and articulations).  But notes-to-skip is, in
itself, general purpose programming.  That's not the interesting part.
The interesting part is how to tie things together, so assume that the
function is already given.

> This is a bit of an unfair case because it's obviously a function
> where imperative programming is probably better suited.

It is a bit unfair since you have not even _tried_ creating a LilyPond
document where this function is defined and used.  You have created a
scrap of source code dangling in the air.  That is not the hard part
about an extension language.

> OK.  Here's some of what I see in D:
>
>   * Basic syntax is close to C/C++/Java/C# making it easy to adapt to from
>     any of these widely-used languages.

And those widely-used language that every musician is comfortable with,
including the concept of inexact arithmetic for rationals.  The kind of
math you learn in the school.

>   * Compiles down to fast native code with performance virtually
>   identical to C/C++, but can also be run in scripting mode.

Nice if I am writing a packet driver.  So if we use it in LilyPond where
C++ is used, we can use almost the same programming style, just with a
performance hit for the pains of porting.

>   * Fast to compile (faster than Go IIRC, _much_ faster than C++).

Too bad that compilation times are not a problem in LilyPond.  The
problem would be rather having to compile and link _at_ _all_ just for
writing a document.

>   * Automatic garbage collection, but this can be disabled if needed.

Why would I disable something that works and makes life easier?  Is it
badly implemented/inefficient?

>   * Inbuilt support for functional programming, enforcement of purity etc.
>     but with a tolerant approach that allows mutation of internal functional
>     variables as long as it has no side-effects (e.g. my naturalizePitch is
>     a pure function, even though the way it's written it has mutation of
>     internal variables).

Can you please explain this in terms a musician would understand?

>   * Thread-safe globals by default, inbuilt support for immutable variables,
>     inbuilt support for both message passing and mutex-based approaches to
>     concurrency.

Can you please explain this in terms a musician would understand?  Also
explain where and why he should acquire the computer science for being
able to write LilyPond files?

>   * Currently a small but very enthusiastic developer and user
>   community, but picking up a growing interest from games developers,
>   scientific programmers, and others who have strong joint
>   requirements for speed, safety and ease of writing/debugging.

Yup.  Sounds like a perfect match to the requirements of musicians.

>   It's also clear there is interest from Facebook and other
>   organizations that have to write large-scale web applications with
>   low per-user energy cost.

A partitura is quite like a large-scale web application, I guess.

> ... and other stuff; but that's enough for now, I think.

Sure, enough.  Just not of the right kind.  The idea was to _solve_
problems, not create them.

-- 
David Kastrup




reply via email to

[Prev in Thread] Current Thread [Next in Thread]