# Cast value to Integer type

Hi everyone, what is the most elegant way to cast a variable into an integer value?

Thanks

1 Like

Can you please give an example of this? What kind of variable of what type?

Ya, sorry I was not so clear. This question is related to this post
Maybe we can continue there because is strictly related to the OSC manipulation.
Thanks @mrreason

1 Like

Ah I see

But let me answer this here anyway because this is a general question I guess. And maybe it's useful for you and/or others.

You can see the type definition of a function with `:t` like

``````:t n
``````

This will return `n :: Pattern Double -> ControlPattern` which means, that the n function needs to receive a Pattern from type `Double`.
The trick is that a `1` as parameter will automatically treat as an `Double` when you use it for the `n` function:

``````n 1
-- (0>1)|n: 1.0f
``````

You can specify the type of such a number with `::Integer` or `::Double`:

``````:t 1::Integer
-- 1::Integer :: Integer
``````

Thats why this results in an error:

``````n 1::Integer
``````

And last but not least I briefly explain my mistake from the other thread `cI` returns a Pattern of `Int`

``````:t cI
-- cI :: Int -> String -> Pattern Int
``````

And cF returns a pattern of type `Double`

``````:t cF
-- cF :: Double -> String -> Pattern Double
``````

Now it should be clear why `cI` won't work for the function `n` but `cF` does.

2 Likes

Oh man, thank you very much for this detailed answer !!

The `t:` maybe will save me through my long journey in learning this language.

Many thanks, really !!

1 Like

Really no problem, I am glad if I could help

One last thing perhaps. In case you are wondering where things like `:t` come from, or how the type system works. TidalCycles is an embedded domain specific language and it's underlying host language is Haskell. That's why you can do something like this:

``````addSix :: Num a => a -> a
addSix x = x + 6

``````

This has nothing to do with Tidal but you will find that many people writing their own functions that look like this or something similar, which comes from Haskell.

1 Like

Hi,

I'm also new to Tidal and Haskell and this question caused (and causes) a little bit of headache for me too. Mixing and matching types needs some practice and getting used to in my experience.

I'm not an expert but afaik the `x :: Type` notation only applies to literals. It's not casting, so you can not use it for variables or functions.

You can do

`a = 1 :: Double`

but you can not do

`b = a :: Integer`

You have to use a function for that. I personally use `floor` or `round` for converting fractionals into integers, and `fromIntegral` for the other way around.

``````let
a = 1.5
b = floor a
c = fromIntegral b
``````

Now `b :: Integral b => b` which can be used as an `Integer` and `c :: Num b => b` which can be used as a Double. I'm not an expert, but this is how I can work around type problems right now. Haskell's type system is a little intimidating if someone is coming from the imperative world, but it's also seems pretty amazing to me.

Cheers,
Mate

P.S.: In my so very humble opinion Tidal should only use Doubles on the UI front and convert to Integers under the hood when needed, for example sample selection or scale expansion. It's not a deal breaker for me, but it can disturb the flow of musical experimentation to fight such a technical detail. Of course it's possible that I just don't see the detail that makes Integers a necessity.. If so, please let me know, I'm curious!

1 Like

That's not exactly it. You can use `::` to declare the type of any value, including functions. But you can't use it to change the type of anything, or convert from one type to another. That's why `b = a :: Integer` fails in the above - you've already declared `a` to be of type `Double`, so can't later treat it as an `Integer`.

You often don't have to use `::` because Haskell will infer the type of things for you, from the context.

I don't think Haskell has the concept of literals, everything is a value, including functions.

If you could share a particular example that's fiddly, we could think about how to make it easier.

1 Like

Thanks for the clarification, you're absolutely right. By 'literal' I meant a fixed value that is represented in the source code. (I searched it and in Haskell's context 'literal' means something else, something definitely beyond my pay grade.)

And here is something that might be a bit more welcoming imho.

``````scale "major" \$ floor <\$> (struct "t*16" \$ range 0 8 \$ sine)
``````

I would prefer this:

``````scale "major" \$ struct "t*16" \$ range 0 8 \$ sine
``````

Thanks again,
Mate

Okay so I think Tidal's current behavior is right in this example and I want to explain why:

for something like the `scale` function you're presumably not wanting to deal with unconstrained microtonality, so it's really only going to make sense if you convert fractional values to whole numbers anyway. but if that's your approach, then I think it should be left to the programmer to decide how the conversion is done. maybe you want to use `floor`, maybe you want to `round`, maybe you want to do something weird like check the third digit of the fractional number and if it's not 0 or 4 play middle c. Who knows!

in that case, I think it's good to rely on the actual semantic meanings of the underlying Haskell types and just go the more idiomatic Haskell solution of using `fmap` (or an infix operator like `<\$>`).

I think the issue here is just better explanations of how things like `fmap` work so it's not a surprise to people who weren't Haskell programmers first, y'know?

Yep I'm very sympathetic to that view @clarissa but with `n` and `note` taking floating point values and supporting microtonality, why shouldn't `scale`? For a pentatonic scale, it could be nice to sometimes go halfway between two notes.

This is where my lack of formal musical training lets me down though - is e.g. 'halfway between two pentatonic notes' ambiguous?

But then I sense that @gadfly16 doesn't actually want that `sine` to produce microtonal notes. In that case, if `scale` accepted floating point numbers, this would work, but not do what is intended:

``````scale "major" \$ struct "t*16" \$ range 0 8 \$ sine
``````

They could put in a `quantise` to fix that though.

``````scale "major" \$ struct "t*16" \$ quantise 1 \$ range 0 8 \$ sine
``````

As an aside I think all values are 'fixed' in Haskell in that sense.. Well there are mutable variables (you update one when you do use e.g. the `d1` function) but only thanks to trickery.

Oh `quantise` does a `round`, it's an alias for `qround`. There's also `qfloor` and `qceiling` if you want that behaviour.

I'd be in favour of changing `scale` to accept floating points if this behaviour makes sense for people.. but it would be a breaking change for people who are currently having to do explicit conversion to integers.

2 Likes

Thanks, with `quantise` the line becomes much more elegant. I didn't know about it.

On @clarissa 's note, since double values can describe all relevant integer values, those custom roundings would be still possible to be made by the user even if `scale` would do an - in that case yet unnecessary - `floor` inside, and since `scale` maps integer steps of a scale to a float that means that supporting microtonal would be still possible. 0 would map to 0, 1 to 0.5, 2 to 1,... for example.

I can relate to maintaining backward compatibility, so it's a suggestion for 2.0 then. Anyway it's a general consideration that I found very helpful in my other projects to keep types at a minimum. It's good for the end user, but it's even better for function developers that they can be sure what to expect and what to give back.

Thanks again!
Mate

No there's not inherently an ambiguity to something like "halfway between the third and fourth notes of a pentatonic scale"! So, you're right, we should probably have an easy way of expressing that.

To meet both the view of "scale as indexing into a discrete set of notes" and "scale as remapping, which includes fractional values" maybe we could just have two versions of scale in Tidal? One based on the standard getScale and the other based on an alternate version like this?

``````getScale' :: Fractional a => [(String, [a])] -> Pattern String -> Pattern a -> Pattern a
getScale' table sp p = (\n scaleName
-> aux (fromMaybe [0] \$ lookup scaleName table) n) <\$> p <* sp
where octave s x = x `div` length s
aux s f = noteInScale s (floor f) + (f-(floor f))*(noteInScale s \$ 1 + floor f)
noteInScale s x = (s !!! x) + fromIntegral (12 * octave s x)
``````

there's nothing clever here it's just interpolating between fractional notes linearly but unless I typoed that should be doing the right thing?

I sometimes want an "unscale" function - such that

``````forall s n : unscale s (scale s n) = n
``````

one use case: I write a melody like `<c e f g>` because that's convenient - but I want to think/transform diatonically (ionian? white keys ...) e.g., add thirds/fifths that are in the scale - not chromatically add `[0,4,7]`.

of course the problem (sort of what you are currently discussing) is what should "unscale" do if the argument is not in the scale. Perhaps drop it?

NB: the "all is float" language already exists, and is called Javascript ... I do agree that numerical conversions can become an obstacle in performance. (I don't perform but I do teach - and it's basically the same.) The "true Haskell" solution would be to use more precise types (not less). For reference, Euterpea has a polymorphic note type - restricted by the ToMusic1 class http://euterpea.com/api/euterpea-api/note-level-api/ because notes can have annotations, pitch can be absolute or relative. It could be used for scales, but I think they don't. I can't judge how practial this is, or would be for Tidal.

I don't quite have the detailed knowledge to contribute to this, but two things occur to me. Firstly, as Tidal is (mostly) used in conjuntion with SuperCollider, it might make sense to have something that leverages the rich scale/tuning module there.

The other thing to point out â€“ maybe this is obvious â€“ is that human pitch perception is logarithmic. So, a linear interpolation between the pitches of C and C# will not give you what a musician would expect, which is a 50 cent difference.

Yeah I get what you mean but isn't 0.5 in Tidal going to, after it goes to supercollider, give you something halfway between C (0) and C# (1)?

Here's how to do that - there's lots of treasure to be found in the superdirt hacks folder!

1 Like