On 05/06/12 08:53, David Kastrup wrote:
I would doubt that this would have been the fault of Scheme. More
likely a problem of the Scheme/LilyPond interface choices, but those
choices don't go away when replacing Scheme.
No, it was the fault of the unfamiliar Scheme syntax. A colleague used to
working with Scheme was able to solve the problems I encountered trivially
without reference to anything LilyPond-specific.
Python is a programming language where simple cut&paste of example code
fails unless you cut and paste whole lines since leading whitespace
matters. I don't call that exactly easy to comprehend.
... which is finnicky and annoying, but doesn't necessarily make the code itself
difficult to understand or tweak. C, C++, Java, D, Go, PHP, JavaScript and even
Ruby and Python share a close enough notational style and a close enough set of
supported programming paradigms (particularly imperative and object-oriented) to
make it fairly easy to jump from one to another.
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.
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;
double alteration;
pure this(int o, int n, double a)
in
{
assert(0 <= n && n <= 6);
assert(-1 <= a && a <= 1);
}
body
{
octave = o;
notename = n;
alteration = a;
}
}
pure auto naturalizePitch(LilyPitch p)
{
// 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;
// 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))
{
a -= 0.5;
n += 1;
}
else if(a < -0.25 && (n == 0 || n == 3))
{
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)
{
a -= 1.0;
n += 1;
}
else if(a < -0.5)
{
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.
This is a bit of an unfair case because it's obviously a function where
imperative programming is probably better suited. However, if you'd like to
give me an example of a LilyPond function where Scheme allows for a much more
elegant expression than C++, I will try and provide a D equivalent.
It's true that the Scheme example above is more concise, but only because in
some cases multiple expressions have been squeezed onto a single line, whereas
I've chosen to spread the D out for ease of reading. However, if you condensed
the D, or expanded out the Scheme, I contend that _the D would still be easier
to follow_, particularly for someone not versed in LISP. Let's see:
//////////////////////////////////////////////////////////////////
pure auto naturalizePitch(LilyPitch p)
{
auto o = p.octave;
auto n = p.notename;
auto a = p.alteration;
if(a > 0.25 && (n == 6 || n == 2)) { a -= 0.5; n += 1; }
else if(a < -0.25 && (n == 0 || n == 3)) { a += 0.5; n -= 1; }
if(a > 0.5) { a -= 1.0; n += 1; }
else if(a < -0.5) { a += 1.0; n -= 1; }
if(n < 0) { o -= 1; n += 7; }
else if(n > 6) { o += 1; n -= 7; }
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);
}
//////////////////////////////////////////////////////////////////
A point I want to emphasize is that D allows you to have both low-level
imperative programming and higher-level programming styles, with elegant syntax
in both cases. So whereas in another case you might have to use a high-level
language for the general program architecture and C/C++ to build highly
efficient individual components, in D you can do both within the same language.
Regarding new languages, while I don't want to re-open the "alphabet
soup" discussion, my suggestion wasn't simply a casual shout-out to a
cool new language; it was a carefully-considered proposal based on
concerns for programming power, ease and flexibility of syntax, code
efficiency and suitability for the next generation of hardware.
Fewer buzzphrases, more substance.
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.
* Compiles down to fast native code with performance virtually identical to
C/C++, but can also be run in scripting mode.
* Fast to compile (faster than Go IIRC, _much_ faster than C++).
* Automatic garbage collection, but this can be disabled if needed.
* 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).
* Thread-safe globals by default, inbuilt support for immutable variables,
inbuilt support for both message passing and mutex-based approaches to
concurrency.
* 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. 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.
... and other stuff; but that's enough for now, I think.
_______________________________________________
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user