Some ATS code for Book "Getting Started with Arduino"

117 views
Skip to first unread message

Kiwamu Okabe

unread,
Apr 22, 2015, 8:50:08 AM4/22/15
to ats-lang-users, ats-lang-users
Hi all,

I wrote some ATS code to convert sample code of Book "Getting Started
with Arduino".

> * Example 01: Blinking LED
> https://github.com/fpiot/arduino-ats/blob/feature/hongwei-style-io/demo/01_blink/DATS/main.dats
> * Example 02: Turn on LED while the button is pressed
> https://github.com/fpiot/arduino-ats/blob/feature/hongwei-style-io/demo/02_button_press/DATS/main.dats
> * Example 03C: Turn on LED when the button is pressed
> https://github.com/fpiot/arduino-ats/blob/feature/hongwei-style-io/demo/03_de_bouncing/DATS/main.dats
> * Example 04: Fade an LED in and out like on a sleeping Apple computer
> https://github.com/fpiot/arduino-ats/blob/feature/hongwei-style-io/demo/04_pwm/DATS/main.dats
> * Example 05: Turn on LED when the button is pressed. Brightness changes
> https://github.com/fpiot/arduino-ats/blob/feature/hongwei-style-io/demo/05_pwm_button/DATS/main.dats
> * Example 06A: Blink LED at a rate specified by the value of the analogue input
> https://github.com/fpiot/arduino-ats/blob/feature/hongwei-style-io/demo/06a_analoginput_blink/DATS/main.dats
> * Example 06B: Set the brightness of LED to a brightness specified by the value of the analogue input
> https://github.com/fpiot/arduino-ats/blob/feature/hongwei-style-io/demo/06b_analoginput_pwm/DATS/main.dats
> * Example 07: Send to the computer the values read from analogue input 0
> https://github.com/fpiot/arduino-ats/blob/feature/hongwei-style-io/demo/07_analoginput_serial/DATS/main.dats

I think the ATS code is more smart than the original C language code. :)

Thank's,
--
Kiwamu Okabe at METASEPI DESIGN

Hongwei Xi

unread,
Apr 22, 2015, 8:59:45 AM4/22/15
to ats-lan...@googlegroups.com
It looks pretty neat :)

I make a minor suggestion:

When using $UN.cast, it is helpful if you can provide a type argument.

For instance,

$UN.cast{int}(xyz), $UN.cast{double}(xyz), $UN.cast{List0(int)}(xyz), etc.

Otherwise, it can be difficult for the reader to figure out the type of the result after
casting.


--
You received this message because you are subscribed to the Google Groups "ats-lang-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.
Visit this group at http://groups.google.com/group/ats-lang-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/ats-lang-users/CAEvX6dkiPM2LcfGzVumRJ-3%2Bj%3DuSGHMxfbXtVSKOiBJFTna7ZQ%40mail.gmail.com.

Message has been deleted

gmhwxi

unread,
Apr 22, 2015, 9:20:29 AM4/22/15
to ats-lan...@googlegroups.com, kiw...@debian.or.jp, ats-lan...@lists.sourceforge.net
Let us take a look at the following code:


implement main () = {
  fun loop
() = {
    val b
= digitalRead (BUTTON)
    val
() = digitalWrite (LED, b)
    val
() = loop ()
 
}
  val
() = pinMode (LED, OUTPUT)
  val
() = pinMode (BUTTON, INPUT)
  val
() = loop ()
}


Clearly, digitalRead should only be called on an output pin.
So you may introduce an abstract type:

absvtype pin(int) // linear type // 0/1: input/output

Then do:

fun digitalRead2 (!pin(OUTPUT)): int = "mac#digitalRead"
fun digitalWrite2 (!pint(INPUT), int): void = "mac#digitalWrite"

It should now be clear where I am headed :)

The problem is that Arduino programs tend to be simple and small.
There is not a lot of motivation for using advanced types in ATS.

Kiwamu Okabe

unread,
Apr 23, 2015, 7:21:08 AM4/23/15
to ats-lang-users
Hi Hongwei,

On Wed, Apr 22, 2015 at 9:59 PM, Hongwei Xi <gmh...@gmail.com> wrote:
> When using $UN.cast, it is helpful if you can provide a type argument.
>
> For instance,
>
> $UN.cast{int}(xyz), $UN.cast{double}(xyz), $UN.cast{List0(int)}(xyz), etc.

Thank's. It fixed my headache on casting.

https://github.com/fpiot/arduino-ats/commit/61777c22bb06be27dd1fb28a2498606e8b671bd6

... However, following change will occur type error... Why?

$ git diff | cat
diff --git a/demo/06a_analoginput_blink/DATS/main.dats
b/demo/06a_analoginput_blink/DATS/main.dats
index 2ac2d57..74e703f 100644
--- a/demo/06a_analoginput_blink/DATS/main.dats
+++ b/demo/06a_analoginput_blink/DATS/main.dats
@@ -11,7 +11,7 @@ implement main () = {
fun loop () = {
val w = analogRead (SENSOR)
val () = digitalWrite (LED, HIGH)
- val () = delay ($UN.cast w)
+ val () = delay ($UN.cast{ulint}(w))
val () = digitalWrite (LED, LOW)
val () = delay ($UN.cast w)
val () = loop ()
$ make
--ship--
patsopt -o DATS/main_dats.c.tmp -d DATS/main.dats
/home/kiwamu/src/arduino-ats/demo/06a_analoginput_blink/DATS/main.dats:
314(line=14, offs=21) -- 331(line=14, offs=38): warning(3): the
constraint [S2Eeqeq(S2Eextkind(atstype_ulint);
S2Eextkind(atstype_uint))] cannot be translated into a form accepted
by the constraint solver.
/home/kiwamu/src/arduino-ats/demo/06a_analoginput_blink/DATS/main.dats:
314(line=14, offs=21) -- 331(line=14, offs=38): error(3): unsolved
constraint: C3NSTRprop(main; S2Eeqeq(S2Eextkind(atstype_ulint);
S2Eextkind(atstype_uint)))
typechecking has failed: there are some unsolved constraints: please
inspect the above reported error message(s) for information.
exit(ATS): uncaught exception:
_2home_2kiwamu_2src_2ATS_2dPostiats_2src_2pats_error_2esats__FatalErrorExn(1025)
../../Makefile.common:61: recipe for target 'DATS/main_dats.c' failed

The "delay" function is defined as following.

fun delay(ms: ulint): void = "mac#"

Kiwamu Okabe

unread,
Apr 23, 2015, 7:28:42 AM4/23/15
to ats-lang-users, ats-lang-users
Hi Hongwei,

On Wed, Apr 22, 2015 at 10:20 PM, gmhwxi <gmh...@gmail.com> wrote:
> Clearly, digitalRead should only be called on an output pin.
> So you may introduce an abstract type:
>
> absvtype pin(int) // linear type // 0/1: input/output
>
> Then do:
>
> fun digitalRead2 (!pin(OUTPUT)): int = "mac#digitalRead"
> fun digitalWrite2 (!pint(INPUT), int): void = "mac#digitalWrite"

Sorry,,, not make sense.
Could you show some application code using the function
"digitalRead2" or "digitalWrite2"?

Brandon Barker

unread,
Apr 23, 2015, 9:46:45 AM4/23/15
to ats-lang-users
I think the idea is that you will get a typechecking error if you now
try to use digitalRead2 on a write-only pin or vice versa for
digitalWrite2?
> --
> You received this message because you are subscribed to the Google Groups "ats-lang-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-user...@googlegroups.com.
> To post to this group, send email to ats-lan...@googlegroups.com.
> Visit this group at http://groups.google.com/group/ats-lang-users.
> To view this discussion on the web visit https://groups.google.com/d/msgid/ats-lang-users/CAEvX6dm3DhjkmMd9%3Dr143bJNPU6ErgDcA8ASyq32z2TV9tdx%2Bw%40mail.gmail.com.



--
Brandon Barker
brandon...@gmail.com

Brandon Barker

unread,
Apr 23, 2015, 9:47:30 AM4/23/15
to ats-lang-users
But yes, I am not immediately sure how to make this work.
--
Brandon Barker
brandon...@gmail.com

Kiwamu Okabe

unread,
Apr 23, 2015, 10:18:20 AM4/23/15
to ats-lang-users
Hi Brandon,

On Thu, Apr 23, 2015 at 10:46 PM, Brandon Barker
<brandon...@gmail.com> wrote:
> I think the idea is that you will get a typechecking error if you now
> try to use digitalRead2 on a write-only pin or vice versa for
> digitalWrite2?

Yes. I think I understand it.
However I can't imagine the application code...

gmhwxi

unread,
Apr 23, 2015, 10:53:33 AM4/23/15
to ats-lan...@googlegroups.com, kiw...@debian.or.jp
You had:

fun delay(ms: ulint): void = "mac#"
fun delay(us: uint): void = "mac#"

The second one overwrites the first one.

Try something like:

fun delay_uint (uint): void = "mac#"
fun delay_ulint
(ulint): void = "mac#"
overload delay
with delay_uint
overload delay
with delay_ulint

gmhwxi

unread,
Apr 23, 2015, 11:09:45 AM4/23/15
to ats-lan...@googlegroups.com, kiw...@debian.or.jp

Instead of treating a pin as a number, we can treat it as a linear resource:

absvtype pin(int(*n*), int(*i/o*))

fun pin_take(int(n)): pin(n,~1) // get the resource
fun pin_return(pin(n, i)): void  // return the resource // ~1: uninitialized

fun pinMode(!pin(n, i) >> !pin(n, j), mode: int(j)): void // for INPUT or OUTPUT

fun digitalRead (!pin(n, 0)): int // [0] for INPUT
fun digitalWrite (!pin(n, 1), data: int): void // [1] for OUTPUT

This probably looks too heavy handed. My original intent is to use the interface to
teach linear types.

Raoul Duke

unread,
Apr 23, 2015, 11:59:47 AM4/23/15
to ats-lang-users
> You had:
> fun delay(ms: ulint): void = "mac#"
> fun delay(us: uint): void = "mac#"
> The second one overwrites the first one.

why/isn't that a compile time error, or warning at least?

Hongwei Xi

unread,
Apr 23, 2015, 12:20:32 PM4/23/15
to ats-lan...@googlegroups.com
Well, this can be a feature as well :)

Imagine the following scenario:

#include "foo.sats" // [delay] is already declared here
fun delay (...): void = "mac#

A warning sounds reasonable. As I see it, the right place for
handling this is in some kind of IDE.

--
You received this message because you are subscribed to the Google Groups "ats-lang-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.
Visit this group at http://groups.google.com/group/ats-lang-users.

Raoul Duke

unread,
Apr 23, 2015, 12:26:18 PM4/23/15
to ats-lang-users
> Well, this can be a feature as well :)
> Imagine the following scenario:
> #include "foo.sats" // [delay] is already declared here
> fun delay (...): void = "mac#
> A warning sounds reasonable. As I see it, the right place for
> handling this is in some kind of IDE.

My knee jerk reaction is to disagree and still think it must be a
compile time error.

Now let us dream contexts where I might cave in. E.g. if there's no
such thing as namespaces, then things are so bad already that we are
forced to do / allow otherwise insanely bad habits, I guess. :-(

BTW is there an ATS lang *spec* somewhere? I could not find it in 2
minutes of looking on the web site. I'm a nerd and want that stuff
readily available. :-)

gmhwxi

unread,
Apr 23, 2015, 1:09:54 PM4/23/15
to ats-lan...@googlegroups.com

On Thursday, April 23, 2015 at 12:26:18 PM UTC-4, Raoul Duke wrote:
> Well, this can be a feature as well :)
> Imagine the following scenario:
> #include "foo.sats" // [delay] is already declared here
> fun delay (...): void = "mac#
> A warning sounds reasonable. As I see it, the right place for
> handling this is in some kind of IDE.

My knee jerk reaction is to disagree and still think it must be a
compile time error.

Well, the current handling of the issue is consistent with the principle
of lexical scoping. I assume that you have no objection to the legality
of the following code:

val x = 1
val x = 2

Then it is only natural to handle the following declarations similarly:

fun foo : int -> int
fun foo : (int, int) -> int

Yes, it is most likely that a mistake is made if some writes this kind of stuff. But ...

Let us imagine that the code is automatically generated (instead of being written
manually).

If it were stated in the C standard that a vacuous label is illegal, then compiling into
C would have been a lot more difficult.


Brandon Barker

unread,
Apr 23, 2015, 1:35:34 PM4/23/15
to ats-lang-users
On Thu, Apr 23, 2015 at 1:09 PM, gmhwxi <gmh...@gmail.com> wrote:

On Thursday, April 23, 2015 at 12:26:18 PM UTC-4, Raoul Duke wrote:
> Well, this can be a feature as well :)
> Imagine the following scenario:
> #include "foo.sats" // [delay] is already declared here
> fun delay (...): void = "mac#
> A warning sounds reasonable. As I see it, the right place for
> handling this is in some kind of IDE.

My knee jerk reaction is to disagree and still think it must be a
compile time error.

Well, the current handling of the issue is consistent with the principle
of lexical scoping. I assume that you have no objection to the legality
of the following code:

val x = 1
val x = 2

Then it is only natural to handle the following declarations similarly:

fun foo : int -> int
fun foo : (int, int) -> int

Yes, it is most likely that a mistake is made if some writes this kind of stuff. But ...

Let us imagine that the code is automatically generated (instead of being written
manually).

If it were stated in the C standard that a vacuous label is illegal, then compiling into
C would have been a lot more difficult.

If I understand correctly, Kotlin and Scala and others all use the convention that val is immutable and var is mutable, so that 

val x = 1
val x = 2

would not compile. Additionally, there seem to be translators going from Java to both of these languages that aren't flawless but work fairly well - still, I take your word for it, just wanted to point this out.
 


Now let us dream contexts where I might cave in. E.g. if there's no
such thing as namespaces, then things are so bad already that we are
forced to do / allow otherwise insanely bad habits, I guess. :-(

BTW is there an ATS lang *spec* somewhere? I could not find it in 2
minutes of looking on the web site. I'm a nerd and want that stuff
readily available. :-)

--
You received this message because you are subscribed to the Google Groups "ats-lang-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.
Visit this group at http://groups.google.com/group/ats-lang-users.

Raoul Duke

unread,
Apr 23, 2015, 1:45:34 PM4/23/15
to ats-lang-users
> val x = 1
> val x = 2

If those are in the same scope then they should at least generate a
warning. Personally I want those to be an outright error. Ditto having
a local var that is the same name as a function input name. Etc.
Shadowing is long-term bad. Even scoped shadowing is something I worry
about, quite seriously, although I don't currently say we should
disallow it.

pseudocode:

{ val x = 1 { val x = 2; print(x); } }

is ethically very different than

{ val x = 1; val x = 2; print(x); }

in my mind.

Even if those are "vars" instead of "vals" per Scala et. al., I
generally consider shadowing to be badness/madness.

$0.02

gmhwxi

unread,
Apr 23, 2015, 2:14:33 PM4/23/15
to ats-lan...@googlegroups.com
I am a big fan of shadowing. For instance,

fun sum (xs: List(int)): int
case+ xs of
| list_nil () => 0
| list_cons (x, xs) => x + sum(xs)


Yes, I can always write:

| list_cons (x, xs2) => x + sum(xs2)

But I consider it to be inferior. Shdowing xs prevents it from being
used by mistake.

gmhwxi

unread,
Apr 23, 2015, 2:16:52 PM4/23/15
to ats-lan...@googlegroups.com
Yes, Java does not allow it, which I find to be very annoying.
That is why we urgently need atscc2java :)

Raoul Duke

unread,
Apr 23, 2015, 2:21:25 PM4/23/15
to ats-lang-users
> But I consider it to be inferior. Shdowing xs prevents it from being
> used by mistake.

I see what you mean.

As in all such things, damned if you do & damned if you don't. With
shadowing we can have mistakes. Without shadowing we can have
mistakes. I do not know enough to know when to choose which, taking in
to consideration the full context every time: host syntax, target
syntax, etc.

And I do find Erlang's single assignment to be noisy, but on the other
hand I believe I've see enough damage from not doing that kind of
thing to respect Erlang's choice (though see e.g. Reia discussions).

Still, I would rather somebody (someday somewhere) try to see what
could be done instead of allowing shadowing like in your example. If
we don't allow shadowing what could be done to manage / avoid /
prevent / detect any mistakes where we use xs instead of xs2? A
usability question.

gmhwxi

unread,
Apr 23, 2015, 6:13:28 PM4/23/15
to ats-lan...@googlegroups.com
By the way, Java 8 does not do tail-call optimization.
Very annoying.

Brandon Barker

unread,
Apr 23, 2015, 6:18:29 PM4/23/15
to ats-lang-users
Ah yes, thanks for the reminder (as I attempt to do functional programming to the extent possible in Java). I do seem to recall Kotlin had to roll their own TCO, but didn't find the details.

Raoul Duke

unread,
Apr 23, 2015, 6:28:35 PM4/23/15
to ats-lang-users
scala too

Kiwamu Okabe

unread,
Apr 24, 2015, 5:41:03 AM4/24/15
to ats-lang-users
Hi Hongwei,

On Thu, Apr 23, 2015 at 11:53 PM, gmhwxi <gmh...@gmail.com> wrote:
> Try something like:
>
> fun delay_uint (uint): void = "mac#"
> fun delay_ulint (ulint): void = "mac#"
> overload delay with delay_uint
> overload delay with delay_ulint

You are right.
However I wouldn't like to change original Arduino API.

http://www.arduino.cc/en/Reference/HomePage

Then, my style is kept on my project.

Kiwamu Okabe

unread,
Apr 24, 2015, 5:43:52 AM4/24/15
to ats-lang-users
Hi Hongwei,

On Fri, Apr 24, 2015 at 12:09 AM, gmhwxi <gmh...@gmail.com> wrote:
> Instead of treating a pin as a number, we can treat it as a linear resource:
>
> absvtype pin(int(*n*), int(*i/o*))
>
> fun pin_take(int(n)): pin(n,~1) // get the resource
> fun pin_return(pin(n, i)): void // return the resource // ~1: uninitialized
>
> fun pinMode(!pin(n, i) >> !pin(n, j), mode: int(j)): void // for INPUT or
> OUTPUT
>
> fun digitalRead (!pin(n, 0)): int // [0] for INPUT
> fun digitalWrite (!pin(n, 1), data: int): void // [1] for OUTPUT
>
> This probably looks too heavy handed. My original intent is to use the
> interface to
> teach linear types.

Thank's for your advice.
Totally I have less experiment on absvtype.
I should try more simple example in "Introduction to Programming in ATS".

Brandon Barker

unread,
Mar 11, 2018, 8:16:15 AM3/11/18
to ats-lang-users
I still find this behavior to be a bit surprising:

#include "share/atspre_staload.hats"

fun immval(): void = let
 val xx: int = 1
 val _ = xx = 2
 val yy: int = 1
 val yy: int = 2
in (
 println!("xx is ", xx);
 println!("yy is ", yy)
) end

implement
main0 () = immval()


The result of running this is

xx is 1                                                                                                                                                                                                                                
yy
is 2  


I'm not against scope-based shadowing either as in the pattern match Hongwei showed above, but personally would prefer if neither of the examples I list were possible; for instance, Scala allows the kind of shadowing we see in the pattern match as the interior of a match case introduces a new scope. But, it doesn't allow the two variants I show. The first assignment (xx) seems to do nothing I can tell, so ideally would be a typecheck error to let the user know something isn't quite right with what they are attempting. The second case (yy) is what we already discussed, and seems even more blatant. This could be fixed by having a separate concept for immutable values, perhaps. Either call it e.g. "ival" for immutable value or, again, ideally just "val" and keep the current functionality in something called "mval" that allows this form of shadowing (or possibly, in place of the shadowing, prefer the explicit mutation in the case of (xx) for "mval" assignments).

Hongwei Xi

unread,
Mar 11, 2018, 8:46:18 AM3/11/18
to ats-lan...@googlegroups.com
There are no assignments here.

The following line binds '_' to the value 'true':

val _ = xx = 2

xx = 2 is a boolean expression; it is not assignment.

Also, the following line means creating a name yy for the
value 1:

val yy: int = 1

Again, no assignment. For assignments, you need to change
'val' to 'var'.


--
You received this message because you are subscribed to the Google Groups "ats-lang-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-users+unsubscribe@googlegroups.com.
To post to this group, send email to ats-lang-users@googlegroups.com.
Visit this group at https://groups.google.com/group/ats-lang-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/ats-lang-users/4c40b2a5-f8ce-4580-8792-ad909502861a%40googlegroups.com.

Brandon Barker

unread,
Mar 11, 2018, 8:50:21 AM3/11/18
to ats-lang-users
Ah, right, I'm still warming up to having "=" used for both assignment and equality depending on placement, sorry for the mixup.

In the second case, then, I guess what I'm suggesting is that the same name shouldn't be allowed to bind more than once in the same scope.
To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.

Hongwei Xi

unread,
Mar 11, 2018, 9:06:13 AM3/11/18
to ats-lan...@googlegroups.com

>>In the second case, then, I guess what I'm suggesting is that the same name shouldn't be allowed to bind more than once in the same scope.

This really a taste, I would argue.

When coding in Java, I use a lot of 'final' variables. I find it annoying that
two 'final' variables can not have the same name if declared in the same scope.

Someone writing C may do:

int x = 0;
x = x + 1;

But a functional programmer (e.g, myself) would do

val x = 0
val x = x + 1

It is the compiler's job to allocate the same location or register
for the two x's (because their use do not overlap). In Java, I would
write

final int x = 0
final int x = x + 1 // this one is not allowed!!!

When C was invented, machines were simple and a programmer
could do very well by allocating variables manually. These days, it is
no longer the case. One needs compiler support anyway. A programmer
should just write code in a functional style and let the compiler take over
allocation of variables completely.

To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-users+unsubscribe@googlegroups.com.
To post to this group, send email to ats-lang-users@googlegroups.com.

Brandon Barker

unread,
Mar 11, 2018, 9:15:56 AM3/11/18
to ats-lang-users
Maybe now isn't the time, but perhaps (in ATS2 or ATS3) there could be scope-based or project-based overrides for certain linting. For instance, the following library is a build plugin and a normal library: http://www.wartremover.org/doc/install-setup.html

In the first sense, as a build plugin, it does project-wide handling of certain "warts",

However, as a library, you can use Java-like annotations to supress errors and warnings.

I suspect it is probably easier to support something like this at the compiler level (which, I believe, dotty intends to do for "Scala 3").
Reply all
Reply to author
Forward
0 new messages