Declaring variables inside a do block (i'm stuck)

Hi, i'm trying to use variables to control euclidean rhythms inside a mask function:

do
  let base = 16
  let dMask = 6
  let dRitmo = 9
  d1 -- bajo
  $ mask ("t(dMask,base)")
  $ n "0(dRitmo,base)"
  # s "deepb"
  # n (run 16)
  # up ((slow (2) $ run 12 + (slow (1/8) $ run 12)) 
  # cut 1

but it does not work:

t> Error in pattern: Syntax error in sequence:
  "0(dRitmo,base)"
      ^  
unexpected "R"
expecting "-", "+", digit, "c", "d", "e", "f", "g", "a", "b", "[", "{", "<", "^", "'", ".", "?", white space or ","

It seems like it didn't recognize the variable I declared :frowning: What am i doing wrong? Thanks in advance!

1 Like

Here is a partial solution, but I don't have an explanation. I'm also learning about the use of variables so I was trying different things. Your euclidean syntax doesn't follow the pattern syntax defined in the Mini-notation section of the user docs. When I used the formal syntax for euclidean I got part of this to work. The "base" variable caused an error, but when I changed it to "dbase" it worked.

do
  let dbase = 16
  let dmask = 6
  let dritmo = 9
  d1 $ mask "t(6,dbase)" $ euclid dritmo dbase $ s "bd"

I couldn't get the mask function to accept the "dmask" variable name, but it did accept the "dbase" variable. (??) Hopefully someone else will post with a deeper explanation.

1 Like

Oh that's better! Hopefully someone knows what's going on :sweat_smile:

I haven't got a available to confirm, but this should work:

let base = 16
    dMask = 6
    dRitmo = 9
in
do
  d1 -- bajo
  $ mask ("t(dMask,base)")
  $ n "0(dRitmo,base)"
  # s "deepb"
  # n (run 16)
  # up ((slow (2) $ run 12 + (slow (1/8) $ run 12)) 
  # cut 1

ie declare the variables before the do block

1 Like

I would be surprised if Haskell variables can be used from mininotation in this fashion. mask ("t(dMask,base)") has the variables in a string - is that actually supported? I hope this works better:mask (euclid dMask base "t")

this wont work, you cannot use haskell variables inside of mininotation, the way to do it is to declare them in the stream via the set functions and accsessed via the ^ operator, this should work:

do
setF "base" 16
setF "dMask" 6
setF "dRitmo" 9

d1
$ mask "t(^dMask,^base)"
$ n "0(^dRitmo,^base)"
# s "deepb"
# n (run 16)
# up (slow (2) $ run 12 + (slow (1/8) $ run 12)) 
# cut 1
4 Likes

variables in a string - is that actually supported?

No. Haskell names (formal parameters for subprograms, or defined with let in the current module, or imported from others) are never available at run-time (the compiler replaces them with addresses), but mini-notation is evaluated at run-time.

(for computer science students: missing the distinction between static semantics (e.g., name resolution, type checking) and dynamic semantics (evaluation) is the price we pay for allowing javascript and python at the start of the curriculum ... to which you might reply: but teaching LISP (and SCHEME) apparently worked fine 60 years ago ...)

From a Tidal user's standpoint, referring to Haskell names from mini-notation is a very natural thing to want - because the distinction between Haskell notation and mininotation appears, at first sight, like some implementation detail that only distracts from writing music.

(entering Innards area briefly) I can think of two "solutions", both ugly, none recommended:

  • ask the current ghci session about the meaning of a name (programmatically, during evaluation)
  • implement let/lambda calculus in mininotation. Don't! because next you want operators, precedences, libraries, types, ...

Oh, and I can't count, because there's also the option to use quasi quotes to make the compiler (ghci) parse application-specific concrete syntax (mininotation) (cf. 6.13. Template Haskell — Glasgow Haskell Compiler 9.8.1 User's Guide) Well ... perhaps? (Yesod Yesod Web Framework Book- Version 1.6 uses quasiquation heavily.)

Back to the immediate topic at hand - the solution shown above uses setF s e to manually connect mininotation identifier s to the value of the Haskell expression e (which could be a Haskell name) that denotes a Pattern. (There is no documentation for setF and mininotation-^?)

Forgive me for rambling, I've never used ^ before, so I find this interesting. E.g., I wondered:

why do these sound different?

tidal> do setI "x" "[c d e f]"; d1 $ n "[^x ^x/4] " # s "superpiano"
tidal> do setF "x" "[c d e f]"; d1 $ n "[^x ^x/4] " # s "superpiano"

does this work?

do setI "x" "[c d]"; setI "y" "^x e" ; d1 $ n "^y f" # s "superpiano"
2 Likes

well setI tries parsing as an integer pattern and setF as a double pattern, so just check:

"[c d e f]" :: Pattern Int
"[c d e f]" :: Pattern Double

and you see that they are parsed to different patterns, because the notename notation is in conflict with the notelength notation for double patterns (notelength notation is yet another thing lacking documentation)

i don't think so, but not sure

Thank you!!! This works like a charm!

aha, I didn't read past the declaration lines, and completely missed the actual usage :wink:

Hi! I come with another related problem:

This works:

setF "base" 16

setF "num" 7

d1
$ s "{~@16, 808:2(^num,^base)@16}"

But this does not (technically it does work, but not in the way I think it's supposed to):

setF "base" 16

setF "num" 7

d1
$ s "{~@16, 808:2(^num,^base)@^base}"

Is it a bug? Does someone knows of a workaround?

from my reading of the source code (https://hackage.haskell.org/package/tidal-1.9.3/docs/src/Sound.Tidal.ParseBP.html#pElongate),
to the right of @, there must be a numerical (rational) literal - there cannot be a pattern, but the variable reference is a pattern.

works as intended (4 is a rational literal)

tidal> parseTPat @String "foo@4" 
Right TPat_Seq [TPat_Elongate (4 % 1) (TPat_Atom (Just ((1,1),(4,1))) ("foo"))]

does something funny? (<4> is a patttern)

tidal> parseTPat @String "foo@<4>" 
Right TPat_Seq [TPat_Elongate (2 % 1) (TPat_Atom (Just ((1,1),(4,1))) ("foo")),TPat_Polyrhythm (Just TPat_Atom (Nothing) (1 % 1)) [TPat_Seq [TPat_Atom (Just ((6,1),(7,1))) ("4")]]]
1 Like

Oooh okay, well that's a shame :frowning: