Autor Thema: Umgang mit Variablen  (Gelesen 3070 mal)

ingmar

  • Gast
Umgang mit Variablen
« am: Samstag, 8. Februar 2014, 18:08 »
hallo,


bin halbwegs neu zu Liliypond und neu in diesem Forum.

Ich möchte gerne innerhalb einer mehrteiligen Partitur gewisse Eigenschaften in Variablen auslagern.

(1) Funktioniert prima:
\version "2.16.2"
\include "parts.ly"
\score {
\transpose c d
\new PianoStaff { <<
\new Staff { \upperpart }
\new Staff { \lowerpart }
>> }
}

(2) Gibt Compiler-Error:
\version "2.16.2"
\include "parts.ly"
TT = \transpose c d

\score {
\TT
\new PianoStaff { <<
\new Staff { \upperpart }
\new Staff { \lowerpart }
>> }
}

Frage: Welchen Denkfehler mache ich?

Gruß,
ingmar

fugenkomponist

  • Gast
Re: Umgang mit Variablen
« Antwort #1 am: Samstag, 8. Februar 2014, 18:35 »
Hallo Ingmar,

willkommen im Forum. Bitte poste möglichst immer ein (kleines) kompilierbares Beispiel, damit dein Problem schnell nachvollziehbar ist (es sei denn, du willst wie im zweiten Fall einen Compiler-Fehler demonstrieren). Das erste Beispiel mag bei dir funktionieren, weil du eine Datei parts.ly hast, in der upperpart und lowerpart definiert sind, aber die haben wir ja nicht.

Was du wahrscheinlich suchst, ist folgendes:
\version "2.16.2"

TT = #(define-music-function
       (parser location theMusic)
       (ly:music?)
       #{
         \transpose c d #theMusic
       #})

\score {
  \TT
  \new PianoStaff {
    <<
      \new Staff { c' d' e' }
      \new Staff { a b c' }
    >>
  }
}
Ein einfacherer Weg fällt mir im Moment nicht ein, aber vielleicht weiß jemand von den erfahreneren Forenmitgliedern noch was; oder du suchst mal im LSR.

Gruß, Malte

Edit: Da frage ich mich gerade: ich kann kein Lisp/Scheme, aber es ist da bestimmt auch wie in Haskell möglich, Funktionen nur teilweise anzuwenden, oder? Denn transpose ist in music-functions-init.ly ja auch mithilfe von #(define-music-function …) definiert, nimmt halt erstmal zwei ly:pitch? als Argumente.

In Haskell würde man tatsächlich schreiben können
transpose :: Pitch -> Pitch -> Music -> Music
transpose p1 p2 m = [...]
myTranspose :: Music -> Music
myTranspose = transpose (Pitch "c") (Pitch "d")
oder so was, wie sähe das in Scheme/LilyPond aus?
« Letzte Änderung: Samstag, 8. Februar 2014, 18:44 von fugenkomponist »

ingmar

  • Gast
Re: Umgang mit Variablen
« Antwort #2 am: Samstag, 8. Februar 2014, 19:17 »
ok dann - hier erst nochmal in kompilierbar kurzform:

(1) - prima:
\version "2.16.2"
\score {
\transpose c d
\new PianoStaff { <<
\new Staff { \relative c'' { c4 d e f } }
\new Staff { \relative c'' { c4 b bes a } }
>> }
}

(2)
\version "2.16.2"
TT = \transpose c d
\score {
\TT
\new PianoStaff { <<
\new Staff { \relative c'' { c4 d e f } }
\new Staff { \relative c'' { c4 b bes a } }
>> }
}

Der Compiler beschwert sich:
/Users/w/Documents/lilypond/morley/test1.ly:4:8: Fehler: Ungültige Fluchtsequenz: »\TT«

        \TT
/Users/w/Documents/lilypond/morley/test1.ly:4:8: Fehler: syntax error, unexpected STRING

        \TT
/Users/w/Documents/lilypond/morley/test1.ly:9:0: Fehler: syntax error, unexpected '}'
}

Ersetze ich nun meine Zeile 2 "TT=..." durch deine, läuft tatsächlich alles einwandfrei. Dafür erstmal danke! Und ansatzweise kann ich mir auch sogar vorstellen, was dein mehrzeiliges Konstrukt eigentlich anstellt...

Aber trotzdem: Was ist falsch an meinem Ansatz? Warum geht das so nicht?

Danke, Gruß,
ingmar

fugenkomponist

  • Gast
Re: Umgang mit Variablen
« Antwort #3 am: Sonntag, 9. Februar 2014, 12:40 »
Und ansatzweise kann ich mir auch sogar vorstellen, was dein mehrzeiliges Konstrukt eigentlich anstellt...
Es definiert eine Funktion TT, die ein Argument theMusic vom Typ ly:music? nimmt. LilyPond-Code innerhalb von Scheme-Code wird in #{ #} geschrieben. Was genau define-music-function tut und warum es noch parser und location in der ersten Liste stehen hat, weiß ich auch nicht … Hab mir auch die music-functions.scm nicht sooo genau angeschaut; aber da wird define-music-function wohl mithilfe von defmacro-public definiert. Was mir auch nichts sagt, weil ich kein Scheme kann.
Zitat
Aber trotzdem: Was ist falsch an meinem Ansatz? Warum geht das so nicht?
Würde mich auch interessieren; ich glaube, wir können hoffen, dass innerhalb der nächsten ein, zwei Wochen irgendein Scheme-Könner hier auftaucht, der uns das vielleicht erzählen kann ;)

ingmar

  • Gast
...und ein weiteres Beispiel
« Antwort #4 am: Sonntag, 2. März 2014, 16:13 »
...und hier noch ein Beispiel:

Folgender Code kompiliert einwandfrei:
\version "2.16.2"

\markuplist \table-of-contents

\bookpart {
\tocItem \markup "Erstes"
\score { { c' d' e' f' g' } }
\header { piece = "Erstes" }
}

\bookpart {
\tocItem \markup "Zweites"
\score { { c'' b' a' g' f' } }
\header { piece = "Zweites" }
}

Nun möchte ich die Titel der Einzelstückchen gerne als Variable herausziehen:

\version "2.16.2"

\markuplist \table-of-contents

\bookpart {
TT = "Erstes"
\tocItem \markup \TT
\score { { c' d' e' f' g' } }
\header { piece = \TT }
}

\bookpart {
TT = "Zweites"
\tocItem \markup \TT
\score { { c'' b' a' g' f' } }
\header { piece = \TT }
}
...und schon gibts vom Compiler eins auf die Mütze (anschließend wird er dann - verständlicherweise - meckern, \TT sei eine "ungültige Fluchtsequenz"...):
/Users/w/Documents/lilypond/_test/test.ly:6:8: Fehler: syntax error, unexpected STRING

        TT = "Erstes"
Ich stehe vor einem Rätsel. Weiß denn immer noch niemand weiter hier?

Gruß,
ingmar

martinmagtenor

  • Gast
Re: Umgang mit Variablen
« Antwort #5 am: Donnerstag, 10. April 2014, 21:03 »
Hallo Ingmar,

ich kann jetzt (noch) nicht schlüssig begründen, warum die Variablenzuweisung in dem book-Kontext nicht zugelassen ist/wird. Aber die Lösung ist einfach:

Stell die Variablenzuweisung davor und alles ist gut:

\version "2.16.2"

\markuplist \table-of-contents

TT = "Erstes"
\bookpart {
\tocItem \markup \TT
\score { { c' d' e' f' g' } }
\header { piece = \TT }
}

TT = "Zweites"
\bookpart {
\tocItem \markup \TT
\score { { c'' b' a' g' f' } }
\header { piece = \TT }
}

infranator

  • Gast
Re: Umgang mit Variablen
« Antwort #6 am: Freitag, 11. April 2014, 12:22 »
Hallo Ingmar,
das könnte auch eine Möglichkeit sein. Kommt ohne scheme-funktion aus.

\version "2.16.2"

TT = d

\score {
\transpose c \TT
\new PianoStaff { <<
\new Staff { \relative c'' { c4 d e f } }
\new Staff { \relative c'' { c4 b bes a } }
>> }
}

martinmagtenor

  • Gast
Re: Umgang mit Variablen
« Antwort #7 am: Freitag, 11. April 2014, 18:50 »
Hallo Ingmar,

so, jetzt versuche ich die Erklärung und ein funktionierendes Beispiel nachzureichen.

Wer sich die Mühe macht, die Lilypond-Dokumentation zu studieren, wird recht bald damit konfrontiert, dass Lilypond und die Programmiersprache Scheme ganz eng verkoppelt sind. Scheme ist eine Sprache, die keine Strenge Trennung zwischen Programmtext und Daten kennt.

Was macht nun Lilypond? Vereinfacht gesagt, es nimmt die .ly-Dateien, macht Scheme-Code daraus und wirft das dem Scheme-Interpreter "vor die Füße".

Irgendwo steht sinngemäß: "Musikalische Ausdrücke sind Scheme-Ausdrücke." Das ist auch der Grund warum man beides Mischen kann.

Die Übersetzung der Lilypond-Dateien ist möglich, weil es eine Syntax für Lilypond gibt. Die Syntax sieht vor, dass man Variablen verwenden kann. Die einfach Schreibweise

<platzhalter>=<inhalt>

ist aber nur auf der "untersten" Ebene (außerhalb der geschweiften Klammern) möglich, denn "drüber" ist alles schon "in der Scheme"-Welt. (Anmerkung: mir ist bewusst, dass das extrem vereinfacht ist, aber manchmal heiligt der Zweck die Mittel ...)

Diese Erkenntnis ist schon die halbe Miete. Wenn man also innerhalb eines book-Blocks ist, kann man die einfache Variablenschreibweise nicht verwenden und muss auf die Scheme-Syntax ausweichen. Die sieht dann so aus: Aus <platzhalter>=<inhalt> wird (define <platzhalter> <inhalt>). Zusätzlich, da es ja eine Lilypond-Datei ist, die vom Lilypond-Parser verarbeitet wird, müssen wir noch ein # vor die öffnende runde Klammer stellen. Fertig ist die Laube.

Damit sieht der ursprüngliche Code so aus, stellt den Lilypond-Interpreter zufrieden und liefert das erwartete Ergebnis:

\version "2.16.2"

\markuplist \table-of-contents

\bookpart {
#(define TT "Erstes")
\tocItem \markup \TT
\score { { c' d' e' f' g' } }
\header { piece = \TT }
}

\bookpart {
#(define TT "Zweites")
\tocItem \markup \TT
\score { { c'' b' a' g' f' } }
\header { piece = \TT }
}

Grüße und schönes Wochenende

Martin

ingmar

  • Gast
Re: Umgang mit Variablen
« Antwort #8 am: Sonntag, 13. April 2014, 10:59 »
Die einfach Schreibweise <platzhalter>=<inhalt> ist aber nur auf der "untersten" Ebene (außerhalb der geschweiften Klammern) möglich, denn "drüber" ist alles schon "in der Scheme"-Welt. (Anmerkung: mir ist bewusst, dass das extrem vereinfacht ist, aber manchmal heiligt der Zweck die Mittel ...)
Danke. Auch wenn das, wie du ankündigst, bei tieferer Erkenntnis nicht mehr so stehen bleiben könnte, ist es für die Praxis sicher sehr hilfreich. Es freut mich vor allem sehr, dass jemand meine Frage nach so langer Zeit wieder ausgräbt und beantwortet, damit hätte ich nicht mehr gerechnet! :-)

Gruß,
ingmar

harm6

  • Gast
Re: Umgang mit Variablen
« Antwort #9 am: Montag, 5. Mai 2014, 19:05 »
Hallo,

bei der Arbeit an einer ganz anderen Sache bin ich auf eine Lösung für das ursprüngliche Problem gestoßen.

\version "2.19.4"

TT = \transpose c d

\score {
\TT
\new PianoStaff { <<
\new Staff { c''4 }
\new Staff { d''4 }
>> }
}
Ich denke es wurde schon hinreichend dargestellt warum dieser Code nicht funktioniert.


Wenn man aber eine scheme-function mit den zwei Argumenten Ausgangspitch und Zielpitch definiert, in der eine music-function definiert wird, die das music-Argument wünscht, so gelingt es den Aufruf dieses music-Arguments so zu "verzögern", daß es erst beim Aufruf mit der entsprechenden Musik eingefordert wird.

\version "2.19.4"
               
my-trans =             
#(define-scheme-function (parser location from to) (ly:pitch? ly:pitch?)
   (define-music-function (parser location music) (ly:music?)
   #{ \transpose $from $to $music #}))
   
tcis = \my-trans c cis

\score {
\tcis
\new PianoStaff { <<
\new Staff { c''4 }
\new Staff { d''4 }
>> }
}

HTH,
  Harm