For an assignment, I am looking for a way to concatenate a string from a list of chars using List.foldBack.
What I've come up with so far:
let (.+) (x1:string) (x2:char) = x1 + System.Char.ToString(x2)
let implode xs:char list = List.foldBack(fun acc elem -> (.+) acc elem) xs ""
This does however give me the following error message:
This expression was expected to have type
char list
but here has type
string
What am I doing wrong, and how can I get the desired result using foldBack
Your annotation :char list applies to implode's return type, not to xs. You need to parenthesize it if you want the latter ((xs:char list)).
List.foldBack needs to take a function with signature 'a -> 'b -> 'b for some 'a and 'b, but (.+) has type string -> char -> string, which doesn't quite match.
Besides of writing (xs : char list), you also need to order the arguments for (.+) correctly.
List.foldBack : ('a -> 'b -> 'b) -> 'a list -> 'b -> 'b
Required (char -> string -> string) -> char list -> string -> string
Actual ... (fun acc elem -> (.+) acc elem) ...
which is : (string -> char -> string)
If you swap acc and elem, which becomes (.+) elem acc, your code will compile.
List.foldBack : ('a -> 'b -> 'b) -> 'a list -> 'b -> 'b
Required (char -> string -> string) -> char list -> string -> string
Actual ... (fun acc elem -> (.+) elem acc)
where (.+) : string -> char -> string
Or as Foggy Finder suggested, change the operator (.+) so that their arguments are swapped (let (.+) (x1:char) (x2:string) = System.Char.ToString(x1) + x2), then we can use List.foldBack (.+) xs "".
Related
I found myself wanting a way to do some codegen around some large variant types in my code, and I found ppx_variants_conv (https://github.com/janestreet/ppx_variants_conv)
The make_matcher method sounds potentially useful to me, but there are no docs and tbh I am struggling to read the example signature:
val make_matcher :
a:(('a -> 'a t) Variant.t -> 'b -> ('c -> 'd) * 'e)
-> b:((char -> 'f t) Variant.t -> 'e -> (char -> 'd) * 'g)
-> c:('h t Variant.t -> 'g -> (unit -> 'd) * 'i)
-> d:((int -> int -> 'j t) Variant.t -> 'i -> (int -> int -> 'd) * 'k)
-> 'b
-> ('c t -> 'd) * 'k
a b c and d labelled arguments correspond to the cases of the variant and the first part of each signature corresponds to the constructor for each case... I get a bit lost after that 🤔
and it seems a odd to me that 'b 'c 'd and 'k appear in the latter part of the signature but not 'e 'f 'g 'h 'i 'j
In the make_matcher function each labeled argument takes a function of two arguments that has a general form, fun v x -> f, y, where v is the first-class variant that represents the corresponding constructor, x is the value that is folded over all matchers-generating functions. The function returns a pair, in which the first constituent, the function f, is actually the matcher that will be called if that variant matches and some value y that will be passed to the next matcher-generating function.
Let's do some examples to illustrate this. First, let's define some simple matcher, e.g.,
type 'a t =
| A of 'a
| B of char
| C
| D of int * int
[##deriving variants]
let matcher init = Variants.make_matcher
~a:(fun v (x1 : char) ->
(fun x -> x+1),Char.code x1)
~b:(fun v (x2 : int) ->
(fun c -> Char.code c),float x2)
~c:(fun v (x3 : float) ->
(fun () -> 0), string_of_float x3)
~d:(fun v (x4 : string) ->
(fun x y -> x + y),[x4])
init
and here's how we can use, it,
# let f,s = matcher '*';;
val f : int t -> int = <fun>
val s : Base.string list = ["42."]
# f (A 10);;
- : int = 11
# f (B '*');;
- : int = 42
# f C;;
- : int = 0
# f (D (1,2));;
- : int = 3
To be honest, I don't know the purpose of the extra parameter that is passed to each matcher-generating function1. Probably, the idea is that depending on the initial parameter we could generate different matchers. But if you don't need this, then just pass () to it and/or define your own simplified matcher that ignores this additional information, e.g.,
let make_simple_matcher ~a ~b ~c ~d =
fst ##Variants.make_matcher
~a:(fun _ _ -> a,())
~b:(fun _ _ -> b,())
~c:(fun _ _ -> c,())
~d:(fun _ _ -> d,())
()
The make_simple_matcher function has an expected type,
a:('a -> 'b) ->
b:(char -> 'b) ->
c:(unit -> 'b) ->
d:(int -> int -> 'b) ->
'a t -> 'b
1) looking into the guts of the code that generates this function doesn't help a lot, as they use the generic name acc for this parameter, which is not very helpful.
I am writing a function that takes a function as input.
This function also takes a function as input.
I want to give labels to both those functions. I have tried:
let first (second: ((third: ('a -> 'b)) -> 'a )) : 'a =
but this gives me a syntax error "type expected" after the signature of third.
What am I doing wrong?
You have some oddly placed parentheses here, which doesn't make a whole lot of sense (hence why the compiler complains), but from your description I believe you want this:
let first (second: (third: 'a -> 'b) -> 'a) : 'a = ...
val first : ((third:'a -> 'b) -> 'a) -> 'a = <fun>
But note also that second here is still not a labeled argument, just the name that the argument will be bound to in the definition. To make it labeled, you need to prefix it with ~:
let first ~(second: (third: 'a -> 'b) -> 'a) : 'a = ...
val first : second:((third:'a -> 'b) -> 'a) -> 'a = <fun>
The difference in notation is because second is not part of the type. You could also have written this as:
let first : (second:(third:'a -> 'b) -> 'a) -> 'a = fun second -> ...
val first : (second:(third:'a -> 'b) -> 'a) -> 'a = <fun>
I want to implement the List.assoc function using List.find, this is what I have tried:
let rec assoc lista x = match lista with
| [] -> raise Not_found
| (a,b)::l -> try (List.find (fun x -> a = x) lista)
b
with Not_found -> assoc l x;;
but it gives me this error:
This expression has type ('a * 'b) list but an expression was expected of type 'a list
The type variable 'a occurs inside 'a * 'b
I don't know if this is something expected to happen or if I'm doing something wrong. I also tried this as an alternative:
let assoc lista x = match lista with
| [] -> raise Not_found
| (a,b)::l -> match List.split lista with
| (l1,l2) -> let ind = find l1 (List.find (fun s -> compare a x = 0))
in List.nth l2 ind;;
where find is a function that returns the index of the element requested:
let rec find lst x =
match lst with
| [] -> raise Not_found
| h :: t -> if x = h then 0 else 1 + find t x;;
with this code the problem is that the function should have type ('a * 'b) list -> 'a -> 'b, but instead it's (('a list -> 'a) * 'b) list -> ('a list -> 'a) -> 'b, so when I try
assoc [(1,a);(2,b);(3,c)] 2;;
I get:
This expression has type int but an expression was expected of type
'a list -> 'a (refering to the first element of the pair inside the list)
I don't understand why I don't get the expected function type.
First off, a quick suggestion on making your assoc function more idiomatic OCaml: have it take the list as the last argument.
Secondly, why are you attempting to implement this in terms of find? It's much easier without.
let rec assoc x lista =
match lista with
| [] -> raise Not_found
| (a, b) :: xs -> if a = x then b else assoc x xs
Something like this is simpler and substantially more efficient with the way lists work in OCaml.
Having the list as the last argument, even means we can write this more tersely.
let rec assoc x =
function
| [] -> raise Not_found
| (a, b) :: xs -> if a = x then b else assoc x xs
As to your question, OCaml infers the types of functions from how they're used.
find l1 (List.find (fun s -> compare a x = 0))
We know l1 is an int list. So we must be trying to find it in an int list list. So:
List.find (fun s -> compare a x = 0)
Must return an int list list. It's a mess. Try rethinking your function and you'll end up with something much easier to reason about.
As a pass-time, I'm trying to implement all kinds of problems that were presented in a course (concerned with Lambda Calculus and various programming concepts) I took at the university. So, I'm trying to implement Church numerals and associated operators in OCaml (also as an exercise in OCaml).
This is the code so far:
let church_to_int n =
n (fun x -> x + 1) 0;;
let succ n s z =
s (n s z)
let zero = fun s z -> z
let int_to_church i =
let rec compounder i cont =
match i with
| 0 -> cont zero
| _ -> compounder (i - 1) (fun res -> cont (succ res))
in
compounder i (fun x -> x)
let add a b = (b succ) a
let mul a b = (b (add a)) zero
So, it seems to work, but then it breaks down. Let's consider these definitions:
let three = int_to_church 3
let four = int_to_church 4
church_to_int (add three four) // evaluates to 7
church_to_int (add four three) // throws type error - see later
I get that the error thrown has to do with the type polymorphism of the Church numerals when they're defined (see SO question), and then it's resolved after the closures are invoked once. However, I don't seem to understand why the type inconsistency error is thrown in this case:
let three = int_to_church 3
let four = int_to_church 4
church_to_int (mul three four) // throws type error - see later
Any thoughts?
The specific errors:
1.
Error: This expression has type (int -> int) -> int -> int but an expression was expected of type ((('a -> 'b) -> 'c -> 'a) -> ('a -> 'b) -> 'c -> 'b) ->
((((int -> int) -> int -> int) -> (int -> int) -> int -> int) ->
((int -> int) -> int -> int) -> (int -> int) -> int -> int) ->
'd
Type int is not compatible with type ('a -> 'b) -> 'c -> 'a
2.
Error: This expression has type ((((('a -> 'b) -> 'c -> 'a) -> ('a -> 'b) -> 'c -> 'b) -> (('d -> 'd) -> 'd -> 'd) -> 'e) ->
((('a -> 'b) -> 'c -> 'a) -> ('a -> 'b) -> 'c -> 'b) ->
(('d -> 'd) -> 'd -> 'd) -> 'e) ->
(((('a -> 'b) -> 'c -> 'a) -> ('a -> 'b) -> 'c -> 'b) ->
(('d -> 'd) -> 'd -> 'd) -> 'e) ->
((('a -> 'b) -> 'c -> 'a) -> ('a -> 'b) -> 'c -> 'b) ->
(('d -> 'd) -> 'd -> 'd) -> 'e
but an expression was expected of type
((((('a -> 'b) -> 'c -> 'a) -> ('a -> 'b) -> 'c -> 'b) ->
(('d -> 'd) -> 'd -> 'd) -> 'e) ->
'e) ->
('f -> 'g -> 'g) -> 'h
The type variable 'e occurs inside
((('a -> 'b) -> 'c -> 'a) -> ('a -> 'b) -> 'c -> 'b) ->
(('d -> 'd) -> 'd -> 'd) -> 'e
Well i was a bit rusty with lambda-calculus, but after few discussions with some wise old men, i came to this answer : YES, writing that way, OCaml's type system do not allow the writing of Church numerals.
The real problem here is with your addition term :
let add a b = b succ a
wich has the following type
(((('a -> 'b) -> 'c -> 'a) -> ('a -> 'b) -> 'c -> 'b) -> 'd -> 'e) -> 'd -> 'e
Where the arguments of add have not the same type. This is a bit sad since we naively expect the addition to be commutative.
You can easily verify this when writing :
let double a = add a a (* produces type error - the type variable occurs ... *)
This error means that you're trying to unify one type with a "bigger" type i.e that contains it (ex: unifying 'a with 'a -> 'a). OCaml does not allow that (unless if you set the -rectypes option wich allows cyclic types).
To understand better what's going on, let's add type annotations to help the typer (i'll change a bit your notations for sake of clarity):
type 'a church = ('a -> 'a) -> 'a -> 'a
let zero : 'a church = fun f x -> x
let succ n : 'a church = fun f x -> f (n f x)
Now let's go back to the add term and annotate it a bit to see what the typer has to say:
let add (a:'a church) b = a succ b (* we only annotate "a" to let the typer infer the rest *)
This produces a very odd type :
'a church church -> 'a church -> 'a church
That gets interesting: why is the first arg typed as an 'a church church?
The answer is the following : Here, a church integer is a value that takes a moving function of type 'a -> 'a (a self-map in mlahematics) that can browse a space, and an starting point ('a) that belongs to that space.
Here, if we specify that the parameter a has type 'a church, than 'a represent the space in which we can move.
Since succ, the moving function of a, operates over the church, than 'a here is it self an 'a church, thus making the parameter a an 'a church church.
This is not at all the type we wanted at the begining ... but that justifies why the type system do not allow your values three and four as both 1st and snd argument of add.
One solution can be to write add in a different way :
let add a b f x = a f (b f x)
Here, both a and b have the same moving function, and thus the same type, but you do not enjoy anymore the beautiful writing with the partial application ...
An other solution which makes you keep this beautiful writing would be to use universal types, that allow a larger kind of polymorphism:
type nat = {f:'a.('a -> 'a) -> 'a -> 'a}
(* this means “for all types ‘a” *)
let zero : nat = {
f=fun f x -> x
}
let succ n : nat = {
f= fun f x -> f (n.f f x)
}
let add (a:nat) (b:nat) = a.f succ b
let double a = add a a (* Now this has a correct type *)
let nat_to_int n =
n.f (fun x -> x + 1) 0;;
let nat_four = succ (succ (succ (succ zero)))
let eight_i = double nat_four |> nat_to_int //returns 8
But this solution is a bit more verbose than your initial one.
Hope it was clear.
If you look at the type of three, you get that:
val three : ('_a -> '_a) -> '_a -> '_a = <fun>
This is simply the value restriction at work. The value restriction is well explained here: https://realworldocaml.org/v1/en/html/imperative-programming-1.html#side-effects-and-weak-polymorphism
To solve it, In this case you can simply eta-expand the function:
let three x = int_to_church 3 x ;;
val three : ('a -> 'a) -> 'a -> 'a = <fun>
This question already has an answer here:
Why does OCaml sometimes require eta expansion?
(1 answer)
Closed 7 years ago.
Why does OCaml change the type of a value of first use when it contains a universal? For example, if we define a Church encoding for tuples, we have:
# let pair x y z = z x y;;
val pair : 'a -> 'b -> ('a -> 'b -> 'c) -> 'c = <fun>
# let first p = p (fun x y-> x);;
val first : (('a -> 'b -> 'a) -> 'c) -> 'c = <fun>
# let second p = p (fun x y -> y);;
val second : (('a -> 'b -> 'b) -> 'c) -> 'c = <fun>
# let foo = pair 1.2 "bob";;
val foo : (float -> string -> '_a) -> '_a = <fun>
# first foo;;
- : float = 1.2
# foo;;
- : (float -> string -> float) -> float = <fun>
# second foo;;
Error: This expression has type (float -> string -> float) -> float
but an expression was expected of type
(float -> string -> string) -> 'a
Type float is not compatible with type string
# let foo = pair 1.2 "bob";;
val foo : (float -> string -> '_a) -> '_a = <fun>
# second foo;;
- : string = "bob"
# foo;;
- : (float -> string -> string) -> string = <fun>
# first foo;;
Error: This expression has type (float -> string -> string) -> string
but an expression was expected of type
(float -> string -> float) -> 'a
Type string is not compatible with type float
Basically, foo has type val foo : (float -> string -> '_a) -> '_a = <fun>, but this changes the first time we project out either the first or second element. Why does this happen?
This called a weak polymorphic type. Lots of questions were asked and answered about this. Feel free to use SO search facilities or read OCaml FAQ. But in short, this is due to value restriction, that usually comes into play when you have partial application or mutable values. In the former case your can strengthen your type with so called eta-expression (in a layman terms, by substituting partial application with normal function invocation). In the latter case, nothing can be made.
As #ivg says, this is the value restriction. Here is how things work if you use eta expansion:
# let pair x y z = z x y;;
val pair : 'a -> 'b -> ('a -> 'b -> 'c) -> 'c = <fun>
# let first p = p (fun x y -> x);;
val first : (('a -> 'b -> 'a) -> 'c) -> 'c = <fun>
# let second p = p (fun x y -> y);;
val second : (('a -> 'b -> 'b) -> 'c) -> 'c = <fun>
# let foo x = pair 1.2 "bob" x;;
val foo : (float -> string -> 'a) -> 'a = <fun>
# first foo;;
- : float = 1.2
# second foo;;
- : string = "bob"