Here I present two ways to write Euler's totient function in ATS. First we write our primality check:
#include "share/atspre_staload.hats"
staload "libats/libc/SATS/math.sats"
staload UN = "prelude/SATS/unsafe.sats"
fn witness(n : int) :<> [ m : nat ] int(m) =
$UN.cast(n)
fn sqrt_int(k : intGt(0)) :<> [ m : nat ] int(m) =
let
var bound: int = g0float2int(sqrt_float(g0int2float(k)))
in
witness(bound)
end
fn is_prime(k : intGt(0)) :<> bool =
case+ k of
| 1 => false
| k =>
begin
let
fnx loop {n : nat}{m : nat} .<max(0,m-n)>. (i : int(n), bound : int(m)) :<> bool =
if i < bound then
if k % i = 0 then
false
else
loop(i + 1, bound)
else
if i = bound then
if k % i = 0 then
false
else
true
else
true
in
loop(2, sqrt_int(k))
end
end
Note the use of witness
to introduce the existential, which is needed in
assure the compiler that sqrt_int(k)
is positive and hence that the
termination metric is well-founded (as sqrt_int(k)
is used as an input to
loop
). The
:<>
in type signatures indicates a function that cannot have side-effects; in
ATS this means that the function is guaranteed to terminate (a stronger
condition than Haskell's purity).
Now we can implement the actual totient function. Our first example uses relatively straightforward recursion:
fn totient(n : intGte(1)) : int =
case+ n of
| 1 => 1
| n =>>
begin
let
fnx loop { k : nat | k >= 2 }{ m : nat | m > 0 && k >= m } .<k-m>. (i : int(m), n : int(k)) : int =
if i >= n then
if is_prime(n) then
n - 1
else
n
else
if n % i = 0 && is_prime(i) && i != n then
(loop(i + 1, n) / i) * (i - 1)
else
loop(i + 1, n)
in
loop(1, n)
end
end
And again using explicit stack allocation:
fn totient(n : intGte(1)) : int =
case+ n of
| 1 => 1
| n =>>
begin
let
fnx loop { k : nat | k >= 2 }{ m : nat | m > 0 && k >= m }{l : addr} .<k-m>. ( pf : !int @ l | i : int(m)
, n : int(k)
, res : ptr(l)
) : void =
if i >= n then
if is_prime(n) then
let
val () = !res := n - 1
in end
else
let
val () = !res := n - 1
in end
else
if n % i = 0 && is_prime(i) && i != n then
let
val () = !res := (!res / i) * (i - 1)
in
loop(pf | i + 1, n, res)
end
else
loop(pf | i + 1, n, res)
var res: int with pf = 1
val () = loop(pf | 1, n, addr@res)
in
res
end
end
Just for fun, here's how to implement the totient function in Haskell:
hsIsPrime :: (Integral a) => a -> Bool
hsIsPrime 1 = False
hsIsPrime x = all ((/=0) . (x mod
)) [2..m]
where m = floor (sqrt (fromIntegral x :: Float))
hsTotient :: (Integral a) => a -> a
hsTotient n = (n * product [ p - 1 | p <- ps ]) div
product ps
where ps = filter (\k -> hsIsPrime k && n mod
k == 0) [2..n]
The Haskell is a good deal slower, but there are certainly advantages in brevity as well.