Übergabe von Wahrheitswert aus Scheme (war: Stringvergleich in Scheme) [GELÖST]

Begonnen von ingmar, Montag, 15. Juli 2024, 15:22

« vorheriges - nächstes »

ingmar

Hallo,

wahrscheintlich ein ganz blöder Fehler – folgender Code kompiliert anstandslos, hat aber nicht das erwartete Ergebnis:
\version "2.20.0"

AAA = "Hallo."
\markup "Test"

#(if ( string=? AAA "Hallo." )
     #{ \markup "JA!" #}
     #{ \markup "NEIN." #} )

Irgendwas muss an dem Vergleich faul sein, aber ich komm einfach nicht dahinter: Es wird weder "JA!" noch "NEIN." ausgegeben.

Sicher fällt euch der Fehler direkt auf...

Gruß,
--ingmar

(EDIT: Klarer formuliert)

Malte

Vor das #(if noch ein \markup setzen funktioniert. (Dafür sind die \markups innerhalb dann optional.)

ingmar

ah, danke! : - )

Es entsteht allerdings die Frage, warum das so ist. Offenbar ist die Übergabe von Guile zu LilyPond nicht ganz so simpel, wie man sich das von außen vorstellt.

Mit der Erzeugung von Strings als Variablen in Scheme und anschließenden Verwendung und Ausgabe der Variablen in LilyPond komme ich klar. Bei einem Boolean krieg ich es nicht hin. Hier ein anderer Versuch, der allerdings nicht kompiliert:

\version "2.20.0"

AAA = "Hallo."
 #( define is-aaa-hallo ( string=? AAA "Hallo." ))
\markup \is-aaa-hallo

LilypPond kommentiert: "Fehler: Keine Textbeschriftung" (was auch immer das heißen mag).

Gibt es irgendwo einen Artikel zu diesem Thema, wo man sich etwas aufschlauen kann? : - )

Danke, Gruß,
--ingmar

Manuela

#3
Was genau willst du erreichen? Soll getestet werden, ob AAA ein String ist?

\version "2.20.0"

%AAA = "Hallo."
AAA = #'(1 . 1)

#(define is-aaa-hallo (if (string? AAA) AAA "AAA ist kein String" ))

\markup \is-aaa-hallo

gibt den Inhalt von AAA aus, wenn AAA ein string ist, ansonsten den Alternativstring (in diesem Fall "AAA ist kein String")

string=? liefert einen Wahrheitswert, der natürlich kein Markup ist

Scheme dokumentation

Wenn du das Ergebnis des Tests als Markup ausgeben willst, musst du es in einen String umwandeln.

\version "2.25.6"

AAA = #'(1 . 1)

#(define (->string x)
  (call-with-output-string
   (lambda (out)
     (display x out))))

#(define is-aaa-hallo (->string (string=? (->string AAA) "Hallo." )))

\markup \line { AAA ist Hallo.: \is-aaa-hallo }
 
\markup #(->string AAA)

wobei zu beachten ist, dass string=? Strings als Argumente erwartet und einen Fehler meldet, wenn dies nicht der Fall ist.
Danke für eure Hilfe
viele Grüße
-- Manuela

ingmar

Zitat von: Manuela am Montag, 15. Juli 2024, 21:40Was genau willst du erreichen? Soll getestet werden, ob AAA ein String ist?

Ich probiere halt mit Scheme rum. Hier will ich einfach wissen, ob der String AAA einen bestimmten Wert hat, eben "Hallo."

Das \markup-Getöse war nur dazu da, auf einfache Weise (aus meiner LilyPond-Umgebung) zu sehen, ob es geklappt hat.

Zitatstring=? liefert einen Wahrheitswert, der natürlich kein Markup ist
ja, logisch. Ich hatte halt ohne nachzudenken unterstellt, dass jeder Datentyp implizit in einen String umgewandelt wird, wenn nötig, hier also "#t" oder auch "##t". In vielen Programmiersprachen ist das so, hier eben nicht.

Die Formulierung "Fehler: Keine Textbeschriftung" ist aus dem sehr isolierten Kontext der \markup-Funktion irgendwie verständlich, im größeren Kontext innerhalb des allgemeinen Textschwalls ist sie IMHO problematisch; unmittelbar verstanden hätte ich aber beispielsweise "Fehler: \markup erwartet String, nicht Boolean". Wahrscheinlich macht eine Diskussion der Fehlermeldungen von LilyPond hier im Forum sehr wenig Sinn.

Danke für deine Hilfe!

--ingmar

harm6

Hallo ingmar :)

zunächst mal grundsätzliches.

Wenn Du in ein, von der Versions-Angabe abgesehen, leeres ly-file einen string schreibst, also:
\version "2.24.3" "whatever"gibts einen error. Denn dieser string könnte z.B. auch der Name einer Funktion sein, deren Definition aber fehlt.

Wenn Du einen scheme-string nimmst:
\version "2.24.3" #"whatever"gibts zwar keinen Fehler, es ist ja valide data, aber sonst nichts, Du hast LilyPond ja nicht gesagt was damit tun...

Du kannst jetzt (wie schon geschrieben worden ist) \markup davor setzen, dann ist LilyPond klar was zu tun ist. Es gibt auch die Möglichkeit $ zu verwenden.
Ganz genau kann ich Dir nicht auseinander setzen, was da passiert, auf jeden Fall werden manche Interpretationsmechanismen quasi kurz geschlossen, also:
\version "2.24.3" $"whatever"
In neueren Versionen gibt es auch die markup-commands \if bzw \unless, die einer Bedingung folgend ein gegebenes markup drucken oder nichts. Die Bedingung muss als procedure mit den Argumenten layout und props formuliert werden. Also:
\version "2.24.3"

AAA = "Hallo."
     
\markup \if #(lambda (layout props) (string=? AAA "Hallo." )) "xxx"
\markup \unless #(lambda (layout props) (string=? AAA "Ciao." )) "yyy"

@Manuela
statt ->string selbst zu definieren, warum nicht das builtin object->string verwenden?

Gruß,
  Harm


ingmar

#6
Zitat von: harm6 am Dienstag, 16. Juli 2024, 11:48In neueren Versionen gibt es auch die markup-commands \if bzw \unless, die einer Bedingung folgend ein gegebenes markup drucken oder nichts.
Whow! – Bloß schade, dass das nur innerhalb von \markup geht. Aber immerhin! Ich bin sicher, dass \if mir dann später an vielen Stellen elegant weiterhelfen wird...

Denn leider habe ich zur Zeit halt nur Version 2.20 zur Verfügung, ein Umzug ist erstmal nicht möglich, das ist für Apple-User offenbar zu kompliziert und zeitraubend (siehe hier). Das kommt später.

Danke jedenfalls für den Hinweis auf das Dollarzeichen! Dollar scheint ja immer noch die Währung zu sein, die man überall versteht, im Scheme- wie im Liliputland... : - ) Aber auch Dollars sind harte Währung, sie kennen nicht True und False, und hier ist $(object->string (string=? AAA "Hallo.")) ein guter Tip. Das klappt auch in 2.20 und hilft weiter.

Gruß, danke,
--ingmar

EDIT: Klarer formuliert.

Manuela

Zitat von: harm6 am Dienstag, 16. Juli 2024, 11:48@Manuela
statt ->string selbst zu definieren, warum nicht das builtin object->string verwenden?
Ganz einfach, ich habe diese Funktion nicht gefunden bei meiner Recherche, habe so etwas wie "tostring" gesucht
Danke für eure Hilfe
viele Grüße
-- Manuela

harm6

Hier noch einige Gedanken, funktionieren auch mit 2.20.
\version "2.20.0"

%%%%%%%%%%%%%%%%%%%%
%% MARKUP
%%%%%%%%%%%%%%%%%%%%

%% Markup-commands \if, \unless von upstream, sowie custom \if-else
#(define-markup-command (if layout props condition? argument)
  (procedure? markup?)
  (if (condition? layout props)
      (interpret-markup layout props argument)
      empty-stencil))

#(define-markup-command (unless layout props condition? argument)
  (procedure? markup?)
  (if (condition? layout props)
      empty-stencil
      (interpret-markup layout props argument)))

#(define-markup-command (if-else layout props condition? argument1 argument2)
  (procedure? markup? markup?)
  (if (condition? layout props)
      (interpret-markup layout props argument1)
      (interpret-markup layout props argument2)))


AAA = "Hallo."
\markup \if #(lambda (layout props) (string=? AAA "Hallo." )) "xxx"
\markup \unless #(lambda (layout props) (string=? AAA "Ciao." )) "yyy"

BBB = "Ciao."
\markup
  \if-else #(lambda (layout props) (string=? AAA "Hallo." )) "true" "false"

%% Funktioniert
$(if #t
  #{ \relative { b4 c d e } #}
  #{ \relative { b'4 a g f } #})

%% Funktioniert nicht, wie bereits diskutiert
#(if #f
  #{ \transpose c ces \relative { b4 c d e } #}
  #{ \transpose c ces \relative { b'4 a g f } #})

%% Hier funktioniert #(if ..) da wir uns *innerhalb* von { ... }, also innerhalb
%% sequentieller Musik bewegen. Dem parser ist hier klar was gemeint ist.
{
  #(if #f
    #{ \transpose c ces \relative { b4 c d e } #}
    #{ \transpose c ces \relative { b'4 a g f } #})
}

%%%%%%%%%%%%%%%%%%%%
%% MUSIK
%%%%%%%%%%%%%%%%%%%%

%% Musikfunktion zum selektieren
musIf =
#(define-music-function (condition m1 m2)(boolean? ly:music? ly:music?)
  (if condition m1 m2))

\musIf ##t
  \relative { b4 c d e }
  \transpose c cis \relative { b4 c d e }

\musIf ##f
  \relative { b4 c d e }
  \transpose c cis \relative { b4 c d e }

Gruß,
  Harm

Manuela

(string=? AAA "Hallo." )
liefert eine Fehlermeldung, wenn AAA nicht vom Typ "string" ist, daher würde ich diese Funktion eher nicht verwenden oder nur in dieser Form

$(object->string (string=? (object->string AAA) "Hallo."))
Danke für eure Hilfe
viele Grüße
-- Manuela

Manuela

Ich habe das Beispiel ein bisschen abgeändert, vll kannst du etwas davon brauchen

\version "2.25.6"

#(define of-type
   (lambda (x)
     (cond
      ((ly:music? x)            "ly:music")
      ((ly:duration? x)         "ly:duration")
      ((ly:book? x)             "ly:book")
      ((ly:context? x)          "ly:context")
      ((ly:context-def? x)      "ly:context-def")
      ((ly:context-mod? x)      "ly:context-mod")
      ((ly:dimension? x)        "ly:dimension")
      ((ly:dir? x)              "ly:dir")
      ((ly:dispatcher? x)       "ly:dispatcher")
      ((ly:duration? x)         "ly:duration")
      ((ly:event? x)            "ly:event")
      ((ly:font-metric? x)      "ly:font-metric")
      ((ly:grob? x)             "ly:grob")
      ((ly:grob-array? x)       "ly:grob-array")
      ((ly:input-location? x)   "ly:input-location")
      ((ly:item? x)             "ly:item")
      ((ly:iterator? x)         "ly:iterator")
      ((ly:lily-lexer? x)       "ly:lily-lexer")
      ((ly:lily-parser? x)      "ly:lily-parser")
      ((ly:listener? x)         "ly:listener")
      ((ly:moment? x)           "ly:moment")
      ((ly:music-function? x)   "ly:music-function")
      ((ly:music-list? x)       "ly:music-list")
      ((ly:music-output? x)     "ly:music-output")
      ((ly:otf-font? x)         "ly:otf-font")
      ((ly:output-def? x)       "ly:output-def")
      ((ly:page-marker? x)      "ly:page-marker")
      ((ly:pango-font? x)       "ly:pango-font")
      ((ly:paper-book? x)       "ly:paper-book")
      ((ly:paper-system? x)     "ly:paper-system")
      ((ly:pitch? x)            "ly:pitch")
      ((ly:prob? x)             "ly:prob")
      ((ly:score? x)            "ly:score")
      ((ly:skyline? x)          "ly:skyline")
      ((ly:skyline-pair? x)     "ly:skyline-pair")
      ((ly:source-file? x)      "ly:source-file")
      ((ly:spanner? x)          "ly:spanner")
      ((ly:spring? x)           "ly:spring")
      ((ly:stencil? x)          "ly:stencil")
      ((ly:stream-event? x)     "ly:stream-event")
      ((ly:translator? x)       "ly:translator")
      ((ly:translator-group? x) "ly:translator-group")
      ((integer? x)     "integer")
      ((rational? x)    "rational")
      ((real? x)        "real")
      ((complex? x)     "complex")
      ((number? x)      "number")
      ((null? x)        "null")
      ((list? x)        "list")
      ((pair? x)        "pair")
      ((string? x)      "string")
      ((vector? x)      "vector")
      ((boolean? x)     "boolean")
      ((char? x)        "char")
      ((symbol? x)      "symbol")
      ((procedure? x)   "procedure")
      ((eof-object? x)  "eof-object")
      ((input-port? x)  "input-port")
      ((output-port? x) "output-port")
      ((macro? x)       "macro")
      ((void? x)        "void")
      ((promise? x)     "promise")
      ((scheme? x)      "scheme")
      (#t "undef")
      )))

#(define-markup-command (vergleich layout props text-1)
   (scheme?)
   (let* ((is-string (string? text-1))
          (mytype (of-type text-1))
          (m (if is-string
                 text-1
                 (object->string text-1))))
     (if is-string
         (if (string=? m "Hallo.")
             (interpret-markup layout props
               #{
                 \markup
                 \line
                 { Der Text $m ist Hallo. }
               #})
             (interpret-markup layout props
               #{
                 \markup
                 \line
                 { Der Text $m ist nicht Hallo. }
               #})
             )
         (interpret-markup layout props
           #{
             \markup
             \line
             { Der Ausdruck $m ist kein String, sondern ein $mytype }
           #})
         )
     ))

\markup \vergleich "xxx"
\markup \vergleich "Hallo."
\markup \vergleich #'(1 . 1)
\markup \vergleich #'()
\markup \vergleich ##f
\markup \vergleich #'#(1 2 3)
\markup \vergleich #(ly:make-moment 1/6)
Danke für eure Hilfe
viele Grüße
-- Manuela

ingmar

Vielen Dank!

Es ist sehr nett, wie Ihr Euch um mich kümmert (und spekuliert, was ich brauchen könnte...)! : - )

Ich glaube, für den Moment komme ich klar. Ich versuche immer, meine Anfragen sehr allgemein zu stellen, damit sie jedem helfen können. Und oft stellt sich dabei heraus, dass das Problem an ganz anderer Stelle lag – oft auch einfach an meiner fehlenden Vertrautheit mit der Scheme-Syntax und den nicht nur hier diskutierbaren Fehlermeldungen.

Gruß,
--ingmar