I figured I'd post this as ATS is quite difficult. Nothing contained in this file is advisable, but by the time you can figure out what's wrong, you won't need it!

Here is our function that takes a filepath (given as a string) and returns the file's contents as a string:

#include "share/atspre_staload.hats"%{^
#include "libats/libc/CATS/string.cats"
let
val ref = fileref_open_opt(s, file_mode_r)
val str: string =
case+ ref of
| ~Some_vt(x) =>
let
val s = strptr2string(fileref_get_file_string(x))
val _ = fileref_close(x)
in
s
end
| ~None_vt() => (println!("could not open file at " + s) ; "")
in
str
end

You can verify this compiles with:

 \$ patscc -DATS_MEMALLOC_LIBC file_read.dats -c -o file_read.o -cleanaft

There's a fair amount going on here. There are three ways of including foreign code, though one is the #include from C. So far, my approach has been to try to staload things when possible and #include if the compiler complains.

Now we can examine the actual code. fileref_open_opt returns a linear type (discussed here), so we pattern match using ~. Note that we have to call fileref_close manually; unfortunately ATS does not detect it if we fail to include that line.

If this isn't totally straightforward, that's fine! This code is for you; you can write something faster later.