Closed kfisler closed 4 years ago
Yes. Very.
I had a thought last night, actually, about these functions: given that the image functions require degrees, but trig functions require and produce radians, what if we defined
data AngleUnit: degree | radian end
As an extra argument to every trig function. Eg, sin(30, degree) is 1/2
.
Then instead of relying on convention or documentation, students can be
explicit and also not have to convert between the two units unless they
really need to.
Thoughts?
On Aug 10, 2016 11:15 AM, "Kathi Fisler" notifications@github.com wrote:
... rather than degrees. Currently, no input units are specified.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/brownplt/pyret-docs/issues/6, or mute the thread https://github.com/notifications/unsubscribe-auth/AA4DwODRdTdxb4oEMJ-0YyH-E48QZfilks5qeer7gaJpZM4JhQPs .
I really like Ben's suggestion. For one thing, we're not even consistent (rotate
takes angles). Second, I can't remember which one it would take. And finally, it's sometimes really useful to provide one and at other times really useful to provide the other. For instance, when I'm doing trig I think in terms of radians, but when I want to use rotate
when drawing a figure, I'm much more likely to want to use degrees.
The best part about Ben's suggestion is that the calls become self-documenting.
All this will make a Pyret-controlled bot much less likely to crash on Mars.
Question: should it be as Ben has specified? What about
data AngleNumber:
| degrees(n :: Number)
| radians(n :: Number)
end
so I can call num-sin(radians(PI))
or rotate(s, degrees(45))
? I know it looks a bit backwards to write the units outside; on the other hand, functions become single argument as people would expect. On the other other hand, maybe forcing people to confront the units is not a bad thing (you can't blindly say num-sin
, you have to say what radians you mean). The advantage to my suggestion is that the number is already wrapped in its units, so I can say, for instance, map
over a list of unit-ed numbers, instead of having those live in parallel lists.
How do we decide between these two options? (Are there any others?)
Why not just define
degree = (2 * num-asin(1)) / 180
and have people use
num-sin(30 * degree)
Requires nothing more than what we already have, and is no more verbose.
Also, we should do something consistent for other things that take unit-ed numbers…
I picked standalone constants, rather than data values with a field, because trig and images and rotations might easily come up well before we introduce data definitions (e.g. the physics folks, who aren't using data at all). So the constants can be treated like keywords, rather than a new concept.
Using a conversion constant is convenient, mostly, but do I multiply to get into degrees, or divide, or what ...? (It's weird that the definition of degrees is in "radians per degree", and multiplying by degrees produces radians.)
A degree
is not "radians per degree". It is a certain constant number of radians, indeed, simply, a constant number.
To specify an angle that is x
degrees, you multiply x
by degree
.
To find out how many degrees there are in an angle, you divide by degree
.
About the benefits of forcing people to specify what units they use, I can see the point for things like distance, mass, time, current, and composites thereof that don't cancel out dimensions. But for a dimensionless quantity like angle, both physics and mathematics implicitly rely on it being a pure ratio rather than a number of units. When we say C = 2 * pi * r
, 2 * pi
is a pure dimensionless ratio. Of course 2 * pi
is also an angle in radians, and the circumference is the special case of an arc being equal to the subtended angle times the radius. Once we start thinking of allowing a choice of units for this angle that must always be specified, lots of simple formulas, even at the high-school level, become very complicated indeed.
I'm reading but not saying much here because I don't have a good sense for what kinds of programs people write using the trig functions (my usage which inspired the remark was quite simple). I do agree with Ben's point that users should have to confront Data prematurely -- we will have users who just want to use trig functions as directly as possible.
@schanzer Do you want to weigh in on this? Let's do something harmonious across various "mathy" uses.
@ds26gte of course a degree is not in "radians per degree", but the constant degree
is exactly the constant of proportionality between degrees and radians, and is indeed radians-per-degree, a dimensionless number that is only meaningful when converting between the two measurement scales.
The problem with saying "to find out how many degrees there are in an angle, you divide by degree
" is twofold: it's asymmetric (why don't you need to divide by radian
, for radians?) and it's unintuitive (I don't need to divide by meter
to get lengths in meters, unless I'm specifying a length only in reference to some other scale of measurement).
Defining a general-purpose units-of-measure system for Pyret is _way, _way__ beyond the scope of the type system we envision for our language, even if it would be super cool. 8-)
Okay, so this is a classic tradeoff between "best pedagogy for beginners" and "best pedagogy for non-beginners". For student who are new to programming, I think exposing them to data:
early is a total non-starter. Teachers who are nervous about programming to begin with will run for the hills. For them, we need to pick radians or degrees and just go with it.
Of course, for non-beginners, this is just a pain in the ass. We have variants, so let's use them to solve the problem!
At the API level, I'd envision something similar to the way the image library handles colors. For beginners, they're just strings. For non-beginners, they're actually Color
s, which must be explicitly declared. Can this be done?
For a teacher who says "I don't want to teach data:
blocks, but I do want radians", we can hand-waive and say "well, there's this function called radians
that will tag a value and preserve its meaning. That's enough of a fudge to get going in radians quickly, without having to cover too much PL.
That leaves the question of what our simple default is: degrees or radians? I vote degrees, for several reasons:
rotate
takes are HS teachers. We want the simple case to satisfy everyone else. rotate
s semantics.data
.I really don't want to claim "there's this function called radians
that will tag a value and preserve its meaning," because that winds up as horrible UX for the return values of functions like asin
and atan
and such -- how do I pull the value back out of them?
And I'm sorry, but I still am not sold on the motivation for a conversion constant here, because we're picking one scale of measure whose conversion constant is the integer 1, and so creating an asymmetry in the API that gets harder to explain later...and also makes the more mathematically useful version of these functions distinctly harder to use later on.
As to your question about "can we mimic colors-vs-strings in this degrees-vs-radians setting", no, I don't think we can. There's a finite enumeration of colors that we presupport; the same is not true for numbers. (And, frankly, using strings for colors is a lousy API, especially when we have the same-named values, without quotes, as actual proper Color
s! But that's a separate discussion...)
I would say the way we handle colors is not exactly exemplary…
Given that we're going to revise the whole color and image library, and make colors be A Thing, as opposed to strings with coincidentally readable names, any further thoughts on this?
... rather than degrees. Currently, no input units are specified.