Evaluating `IO` Actions from REPL - idris

Given:
*lecture2> :let x = (the (IO Int) (pure 42))
Looking at its type, what's the meaning of the MkFFI C_Types String String signature?
*lecture2> :t x
x : IO' (MkFFI C_Types String String) Int
I then attempted to evaluate x from the REPL:
*lecture2> :exec x
main:When checking argument value to function Prelude.Basics.the:
Type mismatch between
IO Int (Type of x)
and
Integer (Expected type)
Also, why doesn't 42 print out in the REPL?

Looking at its type, what's the meaning of the MkFFI C_Types String String signature?
The IO' type constructor is parametrised over the FFI that is available within it. It'll be different depending on e.g. the backend you want to target. Here you have access to the C FFI which is the default one IO picks.
You can find out about these things by using :doc in the REPL. E.g. :doc IO' yields:
Data type IO' : (lang : FFI) -> Type -> Type
The IO type, parameterised over the FFI that is available within it.
Constructors:
MkIO : (World -> PrimIO (WorldRes a)) -> IO' lang a
Also, why doesn't 42 print out in the REPL?
I don't know how :exec x is supposed to work but you can evaluate x in an interpreter by using :x x instead and that does yield a sensible output:
Idris> :x x
MkIO (\w => prim_io_pure 42) : IO' (MkFFI C_Types String String) Int

Related

Printf arguments in OCaml

In OCaml, I obtain an error I do not understand when passing arguments which should work to Printf.printf. It is probably because I do not understand that function completely, but I cannot pin down what does not work.
First, I define a function (used for logging):
utop # let log verbosity level str =
if level <= verbosity then (
Printf.printf "\nLevel %i: " level;
Printf.printf str);;
val log : int -> int -> (unit, out_channel, unit) format -> unit = <fun>
All seems well, but then I obtain this:
utop # log 0 0 "%i" 0;;
Error: This function has type
int -> int -> (unit, out_channel, unit) format -> unit
It is applied to too many arguments; maybe you forgot a `;'.
although the following works:
utop # Printf.printf;;
- : ('a, out_channel, unit) format -> 'a = <fun>
utop # Printf.printf "%i" 0;;
0- : unit = ()
So, how can I define a function which does what log intends to do ?
Edit: Indeed, log 0 0 "%i" 0;; looks like too many arguments (4 instead of 3), but so does Printf.printf "%i" 0;; (2 instead of 1), and it works. With partial application, this gives this:
utop # Printf.printf "%i";;
- : int -> unit = <fun>
utop # log 0 0 "%i";;
Error: This expression has type (unit, unit) CamlinternalFormatBasics.precision
but an expression was expected of type
(unit, int -> 'a) CamlinternalFormatBasics.precision
Type unit is not compatible with type int -> 'a
The printf-like functions are variadic, in the sense that they accept a variable number of arguments. It is not really specific to printf and the family, you can define your own variadic functions in OCaml, this is fully supported by the type system. The only magic of printf is that the compiler translates a string literal, e.g., "foo %d to a value of type format.
Now, let's look at the type of the printf function,
('a, out_channel, unit) format -> 'a
Notice that it returns 'a which is a type variable. Since 'a could be anything it could be also a function. The ('a, out_channel, unit) format is the type of the format string that defines the type of function that is generated by this format string. It is important to understand though, that despite that "foo %d" looks like a string, in fact, it is a special built-in value of type _ format, which has a literal that looks like a string (though not all valid strings are valid literals for the _ format type.
Just to demonstrate that the first argument of printf is not a string, let's try the following,
# Printf.printf ("foo " ^ "%d");;
Line 1, characters 14-29:
1 | Printf.printf ("foo " ^ "%d");;
^^^^^^^^^^^^^^^
Error: This expression has type string but an expression was expected of type
('a, out_channel, unit) format
Now, when we know that printf is not a typical function, let's define a printf-like function ourselves. For that we need to use the kprintf-family of functions, e.g.,
# #show Printf.ksprintf;;
val ksprintf : (string -> 'd) -> ('a, unit, string, 'd) format4 -> 'a
This function takes the function which receives the resulting string which we can log, for example,
# let log fmt = Printf.ksprintf (fun s -> print_endline ("log> "^s)) fmt;;
val log : ('a, unit, string, unit) format4 -> 'a = <fun>
# log "foo";;
log> foo
- : unit = ()
This resulting function looks more like sprintf, i.e., it will play nicely with pretty-printing function that work with string as their output devices (this is a different topic). You may find it more easier to define your logging functions, using either Printf.kfprintf or, much better, using Format.kasprintf or Format.kfprintf. The latter two functions have the following types,
val kasprintf : (string -> 'a) -> ('b, formatter, unit, 'a) format4 -> 'b
val kfprintf : (formatter -> 'a) -> formatter ->
('b, formatter, unit, 'a) format4 -> 'b
But the type of format works with the formatter type (which is an abstraction of the output device) that is the type that the pretty printers (conventionally named pp) are accepting. So the log function defined using the Format module will play better with the existing libraries.
So, using Format.kasprintf we can define your log function as,
# let log verbosity level =
Format.kasprintf (fun msg ->
if level <= verbosity then
Format.printf "Level %d: %s#\n%!" level msg);;
val log : int -> int -> ('a, Format.formatter, unit, unit) format4 -> 'a = <fun>
And here is how it could be used,
# log 0 0 "Hello, %s, %d times" "world" 3;;
Level 0: Hello, world, 3 times
- : unit = ()

The signature for this packaged module couldn't be inferred in recursive function

I'm still trying to figure out how to split code when using mirage and it's myriad of first class modules.
I've put everything I need in a big ugly Context module, to avoid having to pass ten modules to all my functions, one is pain enough.
I have a function to receive commands over tcp :
let recvCmds (type a) (module Ctx : Context with type chan = a) nodeid chan = ...
After hours of trial and errors, I figured out that I needed to add (type a) and the "explicit" type chan = a to make it work. Looks ugly, but it compiles.
But if I want to make that function recursive :
let rec recvCmds (type a) (module Ctx : Context with type chan = a) nodeid chan =
Ctx.readMsg chan >>= fun res ->
... more stuff ...
|> OtherModule.getStorageForId (module Ctx)
... more stuff ...
recvCmds (module Ctx) nodeid chan
I pass the module twice, the first time no problem but
I get an error on the recursion line :
The signature for this packaged module couldn't be inferred.
and if I try to specify the signature I get
This expression has type a but an expression was expected of type 'a
The type constructor a would escape its scope
And it seems like I can't use the whole (type chan = a) thing.
If someone could explain what is going on, and ideally a way to work around it, it'd be great.
I could just use a while of course, but I'd rather finally understand these damn modules. Thanks !
The pratical answer is that recursive functions should universally quantify their locally abstract types with let rec f: type a. .... = fun ... .
More precisely, your example can be simplified to
module type T = sig type t end
let rec f (type a) (m: (module T with type t = a)) = f m
which yield the same error as yours:
Error: This expression has type (module T with type t = a)
but an expression was expected of type 'a
The type constructor a would escape its scope
This error can be fixed with an explicit forall quantification: this can be done with
the short-hand notation (for universally quantified locally abstract type):
let rec f: type a. (module T with type t = a) -> 'never = fun m -> f m
The reason behind this behavior is that locally abstract type should not escape
the scope of the function that introduced them. For instance, this code
let ext_store = ref None
let store x = ext_store := Some x
let f (type a) (x:a) = store x
should visibly fail because it tries to store a value of type a, which is a non-sensical type outside of the body of f.
By consequence, values with a locally abstract type can only be used by polymorphic function. For instance, this example
let id x = x
let f (x:a) : a = id x
is fine because id x works for any x.
The problem with a function like
let rec f (type a) (m: (module T with type t = a)) = f m
is then that the type of f is not yet generalized inside its body, because type generalization in ML happens at let definition. The fix is therefore to explicitly tell to the compiler that f is polymorphic in its argument:
let rec f: 'a. (module T with type t = 'a) -> 'never =
fun (type a) (m:(module T with type t = a)) -> f m
Here, 'a. ... is an universal quantification that should read forall 'a. ....
This first line tells to the compiler that the function f is polymorphic in its first argument, whereas the second line explicitly introduces the locally abstract type a to refine the packed module type. Splitting these two declarations is quite verbose, thus the shorthand notation combines both:
let rec f: type a. (module T with type t = a) -> 'never = fun m -> f m

Create a zero length vector

Given this type for vectors, what's the way to create a zero length vector of a particular type of items?
data Vect : Nat -> Type -> Type where
VectNil : Vect 0 ty
(::) : ty -> Vect size ty -> Vect (S size) ty
VectNil String and all the variations I've tried in the REPL failed.
Is it not correct to expect VectNil to work like the default constructor of the generic List in C# does?
new List<string> (); // creates a zero length List of string
VecNil is value constructor and it accepts implicit type parameter. Here you can see it in REPL:
*x> :set showimplicits
*x> :t VectNil
Main.VectNil : {ty : Type} -> Main.Vect 0 ty
Idris infers values of those implicit parameters from the context. But sometimes context does not have enough information:
*x> VectNil
(input):Can't infer argument ty to Main.VectNil
You can explicitly provide value for implicit parameter using braces:
*x> VectNil {ty=String}
Main.VectNil {ty = String} : Main.Vect 0 String
Or use the the operator to add a type annotation:
*x> the (Vect 0 String) VectNil
Main.VectNil : Main.Vect 0 String
In larger programs, Idris is able to infer the type based on its use site.

How to Compare Types for Equality?

I attempted to compare a String and String, expecting True.
Idris> String == String
Can't find implementation for Eq Type
Then I expected False when comparing a String to a Bool.
Idris> String /= Bool
Can't find implementation for Eq Type
Am I missing an import?
You can't as it would break parametricity, which we have in Idris. We can't pattern match on types. But this would be necessary to write the Eq implementation, for example:
{- Doesn't work!
eqNat : Type -> Bool
eqNat Nat = True
eqNat _ = False -}
Also, if one could pattern match on types, they would be needed in the run-time. Right now types get erased when compiling.
Just to add some simple examples to the above: types can't be pattern matched on, but there's a two parameter type constructor for propositional equality, described in the documentation section on Theorem Proving. Notice that the only constructor, Refl, makes only values of type (=) x x, where both type parameters are the same. (this is ≡ in Agda)
So this will typecheck:
twoPlusTwoEqFour : 2 + 2 = 4
twoPlusTwoEqFour = Refl
so will this:
stringEqString : String = String
stringEqString = Refl
but not this:
stringEqInt : String = Int
stringEqInt = Refl
-- type error: Type mismatch between String and Int
and this needs extra work to prove, because addition is defined by recursion on the left argument, and n + 0 can't be reduced further:
proof : n = n + 0

Why doesn't this short OCaml snippet with Printf.printf work?

I'm a OCaml newbie. I'm playing around with "hello world" type snippets and came across this situation.
Here's a session with the interpreter with some extra comments:
# let average a b =
(a +. b) /. 2.;;
val average : float -> float -> float = <fun>
# average 1. 4.;;
- : float = 2.5
# string_of_float (average 1. 4.);;
- : string = "2.5"
(* this fails...*)
# let _ = Printf.printf (string_of_float (average 1. 4.));;
Error: This expression has type string but an expression was expected of type
('a, out_channel, unit) format =
('a, out_channel, unit, unit, unit, unit) format6
(* yet this works *)
# "hello!";;
- : string = "hello!"
# let _ = Printf.printf "hello!";;
hello!- : unit = ()
(* another failed attempt *)
# let s = string_of_float (average 1. 4.);;
val s : string = "2.5"
# s;;
- : string = "2.5"
# let _ = Printf.printf s;;
Error: This expression has type string but an expression was expected of type
('a, out_channel, unit) format =
('a, out_channel, unit, unit, unit, unit) format6
(* and this also works?? *)
# let _ = Printf.printf "2.5";;
2.5- : unit = ()
So here's the situation. string_of_float (average 1. 4.) returns a string,
just as "hello!" does. When I give "hello!" into Printf.printf, it works
as expected. When I give string_of_float (average 1. 4.) to Printf.printf it fails and tells
me it expected didn't expect a string but that other weird type. But why do "hello!" and "2.5" work then?
What's going on?
There is a kind of "overloading" of the meaning of string literals in OCaml. At compile time, they can either be interpreted as a string, or as a format (which are completely different things in the type system), depending on what the type-checker thinks. If it decides that it should be a format, then the format string is parsed directly at compile-time (that is why it is able to type-check the arguments to printf at compile time). (Unlike C, which parses the string at runtime.) However, there is no simple way to convert from a string into a format at runtime. So when you see Printf.printf "2.5", the "2.5" is actually not a string, but as a special format type that was parsed at compile-time. That is why you cannot substitute a string for it.
On an unrelated note, if you just want to print a string, you might want to use print_string (or print_endline if you want a newline).
Printf.printf "%s" anyStringExpr
will work. The first argument to printf is somewhat magical. (Others will fill in the details.)