Autor Thema: Abhängig davon, ob eine Variable definiert ist,... [GELÖST]  (Gelesen 90 mal)

ingmar

  • Full Member
  • ***
  • Beiträge: 102
Abhängig davon, ob eine Variable definiert ist,... [GELÖST]
« am: Sonntag, 10. Juni 2018, 21:39 »
In diesem Beitrag hatte Harms gezeigt, wie man einen Variablennamen in Scheme zusammenbauen kann, um den Inhalt dieser Variable dann in den LilyPond-Code "einzufliegen":

\version "2.19.64"

A-music = \relative { c'4 d e f g1 }
A-titel = "c bis g"

B-music = \relative { g'4 f e d c1 }
B-titel = "g bis c"

myscore = #(define-scheme-function ( pointer) ( string?)
#{ \score {
    \header {
      piece = #(eval-string (format #f "~a-titel" pointer))
    }
    \new Staff { #(eval-string (format #f "~a-music" pointer)) }
}
#})

\myscore "A"
\myscore "B"

Mit diesem Ansatz bin ich ein ganzes Stück weit gekommen. Ich habe aber zwei Fälle gefunden, wo mir doch noch etwas Wesentliches fehlt:

Fall 1: Ich möchte für den Fall, dass die anstehende Variable nicht definiert ist, einen Defaultwert festlegen. – Codierungsversuch:

\version "2.19.64"

C-music = \relative { f'4 a c f, e1 }
C-titel = "Definierter Titel:" % <-- diese Zeile auskommentieren!

myscore = #(define-scheme-function ( pointer) ( string?)
  (if (not (defined? (eval-string (format #f "'~a-titel" pointer))))
    (let (eval-string (format #f "'~a-titel" pointer)) "Default-Titel"))
#{ \score {
    \header {
      piece = #(eval-string (format #f "~a-titel" pointer))
    }
    \new Staff { #(eval-string (format #f "~a-music" pointer)) }
  }
#})

\myscore "C"

Dies läuft ebenfalls problemlos - bis man die dritte Zeile "C-titel" auskommentiert. Fehlermeldung lautet "Bad binding eval-string". Die Zeile, die mit (let.. beginnt, hat offenbar noch einen Fehler. Kann es wieder das alte Problem sein, dass man eine Variablendefinition innerhalb des \score einfach nicht vornehmen darf?


Fall 2: Ebenfalls abhängig davon, ob eine Variable definiert ist, möchte ich innerhalb der \score- Definition einen \this-Abschnitt anlegen oder nicht. – Codierungsversuch:

\version "2.19.64"
D-music = \relative { e'4 g c e, f1 }
D-instrument = "Saxophon"

myscore = #(define-scheme-function ( pointer) ( string?)
#{ \score
  #(if (defined? (eval-string (format #f "'~a-instrument" pointer)))
    ( #{ \with instrument = #(eval-string (format #f "~a-instrument" pointer)) #})
  {
\new Staff { #(eval-string (format #f "~a-music" pointer)) }
  }
#})

\myscore "D"
...das schlägt gleich richtig fehl; ich hab verschiedene Varianten probiert, finde aber keinen Weg, ein \with { ... } von Bedingungen abhängig zu machen.

habt Ihr einen Tip? Sicher ist die Lösung wieder ganz einfach... : - )

Danke und Gruß,
--ingmar
« Letzte Änderung: Sonntag, 17. Juni 2018, 20:54 von ingmar »

harm6

  • Sr. Member
  • ****
  • Beiträge: 367
Antw:Abhängig davon, ob eine Variable definiert ist,...
« Antwort #1 am: Montag, 11. Juni 2018, 01:44 »
Hallo Ingmar,

mittlerweile denke ich, daß (eval-string ...) nicht die beste Wahl ist.
ly:parser-lookup scheint mir momentan vielversprechender, auch wenn man strings zu symbols umwandeln muß, was umständlich ist.

\version "2.19.64"

%D-music = \relative { e'4 g c e, fis1 }
%D-titel = "Definierter Titel:"
%D-instrument = "Saxophon"

myscore = #(define-scheme-function (pointer) ( string?)
#{
  \score {
    \header {
      piece =
        #(let ((sym (string->symbol (format #f "~a-titel" pointer))))
          (if (defined? sym)
              (ly:parser-lookup sym)
              "foo"))
    }
    \new Staff
      \with {
        instrumentName =
          #(let ((sym (string->symbol (format #f "~a-instrument" pointer))))
            (if (defined? sym)
                (ly:parser-lookup sym)
                '()))
      }
      {
          #(let ((sym (string->symbol (format #f "~a-music" pointer))))
            (if (defined? sym)
                (ly:parser-lookup sym)
                (empty-music)))
      }
  }
#})

\myscore "D"

Gruß,
  Harm

ingmar

  • Full Member
  • ***
  • Beiträge: 102
re: Abhängig davon, ob eine Variable definiert ist,...
« Antwort #2 am: Montag, 11. Juni 2018, 18:14 »
Vielen Dank, Harm!

Das nötige Umwandeln in Symbole macht mir nichts aus. Deine Beispiele funktionieren hervorragend; wenn ich sie dann in meinen Code einbaue, gibts allerdings wieder Fehlermeldungen, obwohl ich mir einbilde, es genauso zu machen... Ich werde natürlich versuchen, diese Fehler zu analysieren und zu Minimalbeispielen einzudampfen.

Malte hatte in seinem ersten Post ly:parser-include-string verwendet, du hast erst eval-string, dann ly:parser-lookup verwendet. Ich frage mich natürlich, was die Unterschiede sind – und ob ich sie verstehen würde...

Gruß,
--ingmar
« Letzte Änderung: Montag, 11. Juni 2018, 21:23 von ingmar »

harm6

  • Sr. Member
  • ****
  • Beiträge: 367
Antw:Abhängig davon, ob eine Variable definiert ist,...
« Antwort #3 am: Montag, 11. Juni 2018, 21:20 »
Soweit ich das auf die Schnelle sagen verlangt ly:parser-include-string ein string-argument, welches zu einem musikalischen Ausdruck evaluiert werden kann, ist also seht limitiert.
Später hatte Malte (module-ref (current-module) ...) verwendet. Aber genauso wie eval-string gibts einen error wenn das Argument nicht definiert ist.
ly:parser-lookup jedoch retourniert '() für ein nicht definiertes Argument, damit kann man besser umgehen.

Es gibt noch weitere Unterschiede, aber das ist der für die Anwendung hier entscheidende, imho.

Gruß,
  Harm

ingmar

  • Full Member
  • ***
  • Beiträge: 102
re: Abhängig davon, ob eine Variable definiert ist,...
« Antwort #4 am: Montag, 11. Juni 2018, 21:23 »
Ah, OK. Danke!

--ingmar

ingmar

  • Full Member
  • ***
  • Beiträge: 102
re: Abhängig davon, ob eine Variable definiert ist,...
« Antwort #5 am: Mittwoch, 13. Juni 2018, 18:49 »
Mein Problem hatte offenbar damit zu tun, dass du in deinem Code eine Variable sym definierst, was in meinem Zusammenhang nicht geschmeckt hat (Variablendefinition/-zuweisung geht halt nicht überall). Habs umgangen, und damit läuft alles, wie es soll.

Danke,
--ingmar
« Letzte Änderung: Donnerstag, 14. Juni 2018, 06:21 von ingmar »

ingmar

  • Full Member
  • ***
  • Beiträge: 102
Scheme-Variable in einem Key-Value-Paar
« Antwort #6 am: Sonntag, 17. Juni 2018, 10:57 »
Eine Frage ist aber noch offen! An manchen Stellen in LilyPond müssen einfach Key/Value-Paare stehen, beispielsweise innerhalb von \paper. Unabhängig einmal von der (für mich gelösten) Frage der Evaluierung von Variablennamen stellt sich hier noch die Frage nach der richtigen Syntax, wenn wir uns innerhalb eines durch Scheme erzeugten #{...#}-Blocks befinden und die in Scheme vorhandene Variable auswerten wollen.

Hier mehrere Versuche – je eine auskommentierte Zeile, die beim Entkommentieren aus verschiedenen, aber wohl ähnlichen Gründen fehlschlägt:

\version "2.19.64"

mypaper = #(define-scheme-function (mymargin) (integer?) #{
\paper {
% top-margin = \mymargin
% top-margin = #(mymargin)
% top-margin = #(eval mymargin)
% top-margin = #(ly:parser-lookup (mymargin))
}
#})

\mypaper 30
\score {
\relative { c' e d f e g f a g1\fermata }
}

Es sollte eigentlich nicht schwer sein, aber ich komm nicht drauf! Wie kann man das angehen, und welchen Denkfehler mache ich?


Danke, Gruß,
--ingmar

harm6

  • Sr. Member
  • ****
  • Beiträge: 367
Hallo Ingmar,

eine solche lokale Variable rufe innerhalb von #{ #} mit #mymargin oder $mymargin auf.
#mymargin ruft es direkt, $mymargin eine Kopie. Hier ist der Unterschied belanglos, aber falls das Argument Musik ist, so bevorzuge $.
Ansonsten kann es passieren, daß das Musik-Argument destruktiv verändert wird und nicht mehr im Original zur Verfügung steht.

Im Übrigen
(1)
\mymargin würde eine toplevel Variable aufrufen können, keine lokale.
(2)
#(mymargin)
Durch die Klammern versucht der scheme-interpreter die procedure `mymargin` auszuführen. Eine solche procedure gibt es aber nicht.
(3)
#(eval mymargin)
Hier ist die procedure `eval`, die versucht `mymargin` innerhalb einer nicht gegebenen "Umgebung" zu evaluieren.
Deshalb der error:
Wrong number of arguments to #<primitive-procedure eval>
#(eval mymargin (current-module)) würde funktionieren, aber warum der Umstand...
Eine Zahl evaluiert zu nichts anderem als eben dieser Zahl
(4)
#(ly:parser-lookup (mymargin))
Funktioniert nicht wegen der Klammern, siehe oben.
ly:parser-lookup erwartet ein symbol (den Namen dessen was Du im parser nachschauen möchtest)
(ly:parser-lookup 'mymargin) wäre zwar korrekte Syntax, scheitert aber da `mymargin` eine lokale Variable ist, die der parser gar nicht zu sehen bekommt, afaict.


Gruß,
  Harm


ingmar

  • Full Member
  • ***
  • Beiträge: 102
re: Abhängig davon, ob eine Variable definiert ist,...
« Antwort #8 am: Sonntag, 17. Juni 2018, 19:20 »
Danke! Bei einigen davon hätte ich ja selber draufkommen können.. : - (

Nachher ist man immer klüger.

Gruß,
--ingmar