when trying to write a simple program for solving a toy SAT problem, I came across the following problem I cannot get my head around.
I have a type variable which is defined as follows:
type prefix =
| Not
| None
type variable =
| Fixed of (prefix * bool)
| Free of (prefix * string)
from which I can build a clause of type variable list and a formula of type clause list. Essentially this boils down to having a formula in
either CNF or DNF (this has less to do with the problem).
When now trying to simplify a clause I do the following:
Filter all Fixed variables from the clause which gives a list
Simplify the variables (Fixed(Not, true) => Fixed(None, false))
Now I have a list containing just Fixed variables which I now want to combine to a single Fixed value by doing something like this
let combine l =
match l with
| [] -> []
| [x] -> [x]
| (* Get the first two variables, OR/AND them
and recurse on the rest of the list *)
How would I achieve my desired behavior in a functional language? My experience in OCaml is not that big, I am rather a beginner.
I tried doing x::xs::rest -> x <||> xs <||> combine rest but this does not work. Where <||> is just a custom operator to OR the variables.
Thanks for your help.
How about using the neat higher order functions already there?
let combine = function
| x::xs -> List.fold_left (<||>) x xs
| [] -> failwith "darn, what do I do if the list is empty?"
For clarification:
List.fold_left : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
takes a function that gets the running aggregate and the next element of the list; it returns the new aggregate; then we need an initial value and the list of items to fold over.
The use of your infix operator <||> in brackets makes it a prefix function so we can give it to List.fold_left just like that -- instead of writing (fun a b -> a <||> b).
If you have a neutral element of your <||> operator, lets call it one, we could write it even more concise:
let combine = List.fold_left (<||>) one
As List.fold_left requires three arguments and we only gave it two, combine here is a function of variable list -> variable as the previous one. If you wonder why this works, check out the concept of currying.
Here's my attempt:
let rec combine l =
match l with
| [] -> []
| [x] -> [x]
| a :: b :: rest -> combine ((a <||> b) :: rest)
Note you need let rec.
Related
I know List.map uses recursion, I'm just wondering if there's a simpler way to implement map function without using recursion.
I know for reverse, I can simplify it into:
(* given *)
type 'a list =
| []
| (::) of 'a * 'a list
let nil : 'a list = []
let cons (hd : 'a) (tl : 'a list): 'a list = hd :: tl
let reverse (ls : 'a list): 'a list =
List.fold_left (Fun.flip cons) [] ls
Right now I'm thinking about using ##(the application operator), %(the function composition operator), and maybe Fun.flip or List.fold_left to do it, can anyone give me some hint about that?
I have tried the following, but OCaml raised an error about it.
List.fold_left (fun x -> f x) [] ls
List.fold_left uses recursion, so presumably you're looking to avoid use of the rec keyword, rather than recursion at all.
You note in comments trying:
List.fold_left (fun x -> f x) [] ls
But the function passed to List.fold_left must take two arguments: the initial state, and the first element of the list. Fun.flip cons worked in your reverse function because it does take two arguments.
Note: fun x -> f x is the same as writing f.
If you initial state is a list, you need to do something to that list in the function you pass to List.fold_left, like adding the result of f x to the front of it. Since this builds the list backwards, you will need to reverse the result. This is where ## will come in handy.
let map f lst =
List.(
rev ## fold_left (fun i x -> f x :: i) [] lst
)
exception Empty_list
type 'a stream = Stream of 'a * (unit -> 'a stream) | Nil
let shead s = match s with
| Stream (a, _) -> a
| Nil -> raise Empty_list
let stail s = match s with
| Stream (_, s) -> s ()
| Nil -> raise Empty_list
let stream_to_list s =
let rec stream_to_list s accumulator = match s with
| Nil -> accumulator
| Stream (_, _) -> stream_to_list (stail s) (shead s :: accumulator)
in List.rev (stream_to_list s [])
The flatten function would take an arbitrarily nested set of streams and produce a completely flattened version that's a result of an inorder traversal of the nesting structure and contains only the leaves. This would mean that the result of shead on each member of this new thing would return something that was not a stream.
The idea is that stream_to_list (flatten s) would give back a list in which no element was a stream.
Your desired function is ill-typed and cannot exist in a language with parametric polymorphism like OCaml: 'a stream -> 'b stream where 'b is not a stream is not a valid type.
Parametric polymorphism requires that polymorphic functions does not change their behavior in function of the type of their argument. This useful both in term of semantics, types can be erased once type checking is done, and for type theoretical reason: proofs (aka the program) cannot inspect the theorem (aka the type) that they are trying to prove.
If you want to flatten multiple times a nested streams they are two options:
if the nested level is known statically, you can use flatten multiple times. Note that it is straightforward to flatten a number of time exponential with the size of the code
let flatten16 x =
let flatten2 x = flatten (flatten x) in
let flatten4 x = flatten2 (flatten2 x) in
let flatten8 x = flatten4 (flatten4 x) in
flatten8 (flatten8 x)
This is completely sufficient in practice since types don't grow exponentially in human written code.
If the level of nesting is arbitrary, the level of nesting needs to be visible on the value level (which is already needed to construct the stream). This can be achieved with the following variant type:
type 'a nested_seq = Seq of 'a Seq.t | Nested of 'a Seq.t nested_seq
(Your type is equivalent to Seq.t from the standard library)
Then flattening a 'a nested_seq to a 'a Seq.t is a well-defined notion and that can be done with some polymorphic recursion:
let rec flatten: 'a. 'a nested_seq -> 'a Seq.t = fun x ->
match x with
| Seq x -> x
| Nested s -> Seq.flat_map Fun.id (flatten s)
(* or `Seq.concat (flatten s)` in OCaml 4.13 or with a sequence libray *)
Aside: shead and stail are anti-patterns: in order to safely use those functions, you need to pattern match their future argument, and them discard the matched value in each branches.
In other words,
let head s =
match s with
| Nil -> None
| Stream _ -> Some (shead s)
is both less clear and less safe than
let head s =
match s with
| Nil -> None
| Stream (s, _) -> Some s
(The option functions are useful to compose with generic option functions (from the option monad for instance)).
I meet an error about subtyping.
For this code, List.map (fun ((String goal_feat):> Basic.t) -> goal_feat) (goal_feats_json:> Basic.t list).
I meet the following error in vscode:
This expression cannot be coerced to type
Yojson.Basic.t =
[ Assoc of (string * Yojson.Basic.t) list
| Bool of bool
| Float of float
| Int of int
| List of Yojson.Basic.t list
| Null
| String of string ];
it has type [< String of 'a ] -> 'b but is here used with type
[< Yojson.Basic.t ].
While compiling, I meet the following error.
Error: Syntax error: ')' expected.
If I change the code to List.map (fun ((String goal_feat): Basic.t) -> goal_feat) (goal_feats_json:> Basic.t list), which useq explicit type cast instead of subtyping, then the error disappeared. I can not understand what is the problem with my code when i use subtyping. Much appreciation to anyone who could give me some help.
First of all, most likely the answer that you're looking for is
let to_strings xs =
List.map (function `String x -> x | _ -> assert false) (xs :> t list)
The compiler is telling you that your function is handling only one case and you're passing it a list that may contain many other things, so there is a possibility for runtime error. So it is better to indicate to the compiler that you know that only the variants tagged with String are expected. This is what we did in the example above. Now our function has type [> Yojson.Basic.t].
Now back to your direct question. The syntax for coercion is (expr : typeexpr), however in the fun ((String goal_feat):> Basic.t) -> goal_feat snippet, String goal_feat is a pattern, and you cannot coerce a pattern, so we shall use parenthesized pattern here it to give it the right, more general, type1, e.g.,
let exp xs =
List.map (fun (`String x : t) -> x ) (xs :> t list)
This will tell the compiler that the parameter of your function shall belong to a wider type and immediately turn the error into warning 8,
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
(`Bool _|`Null|`Assoc _|`List _|`Float _|`Int _)
which says what I was saying in the first part of the post. It is usually a bad idea to leave warning 8 unattended, so I would suggest you to use the first solution, or, otherwise, find a way to prove to the compiler that your list doesn't have any other variants, e.g., you can use List.filter_map for that:
let collect_strings : t list -> [`String of string] list = fun xs ->
List.filter_map (function
| `String s -> Some (`String s)
| _ -> None) xs
And a more natural solution would be to return untagged strings (unless you really need the to be tagged, e.g., when you need to pass this list to a function that is polymorphic over [> t] (Besides, I am using t for Yojson.Basic.t to make the post shorter, but you should use the right name in your code). So here is the solution that will extract strings and make everyone happy (it will throw away values with other tags),
let collect_strings : t list -> string list = fun xs ->
List.filter_map (function
| `String s -> Some s
| _ -> None) xs
Note, that there is no need for type annotations here, and we can easily remove them to get the most general polymoprhic type:
let collect_strings xs =
List.filter_map (function
| `String s -> Some s
| _ -> None) xs
It will get the type
[> `String a] list -> 'a list
which means, a list of polymorphic variants with any tags, returning a list of objects that were tagged with the String tag.
1)It is not a limitation that coercion doesn't work on patterns, moreover it wouldn't make any sense to coerce a pattern. The coercion takes an expression with an existing type and upcasts (weakens) it to a supertype. A function parameter is not an expression, so there is nothing here to coerce. You can just annotate it with the type, e.g., fun (x : #t) -> x will say that our function expects values of type [< t] which is less general than the unannotated type 'a. To summarize, coercion is needed when you have a function that accepts an value that have a object or polymorphic variant type, and in you would like at some expressions to use it with a weakened (upcasted type) for example
type a = [`A]
type b = [`B]
type t = [a | b]
let f : t -> unit = fun _ -> ()
let example : a -> unit = fun x -> f (x :> t)
Here we have type t with two subtypes a and b. Our function f is accepting the base type t, but example is specific to a. In order to be able to use f on an object of type a we need an explicit type coercion to weaken (we lose the type information here) its type to t. Notice that, we do not change the type of x per se, so the following example still type checks:
let rec example : a -> unit = fun x -> f (x :> t); example x
I.e., we weakened the type of the argument to f but the variable x is still having the stronger type a, so we can still use it as a value of type a.
I'm learning about the map and fold functions. I'm trying to write a function that takes a list and returns a list with all of the values in the original, each followed by that value's double.
Example: add_dbls [2;5;8] = [2;4;5;10;8;16]
Everything I try results in a list of lists, instead of a list. I'm struggling to come up with a better approach, using either map or fold (or both).
This is what I came up with originally. I understand why this returns a list of lists, but can't figure out how to fix it. Any ideas would be appreciated!
let add_dbls list =
match list with
| h::t -> map (fun a-> [a;(a*2)]) list
| [] -> []
Also, my map function:
let rec map f list =
match list with
| h::t -> (f h)::(map f t)
| [] -> []
You are nearly there. As you have observed, since we get list of lists, we need to flatten it to get a final list. List.concat function does exactly that:
let add_dbls list =
let l =
match list with
| h::t -> List.map (fun a -> [a;(a*2)]) list
| [] -> []
in
List.concat l
Here is the updated function that that computes the output that you require.
Now the output of add_dbls [2;5;8] = [2;4;5;10;8;16].
Although this works, it probably isn't efficient as it allocates a new list per item in your original list. Below are variations of the same function with different characteristics which depend on the size of l.
(* Safe version - no stack overflow exception. Less efficient(time and size) than add_dbls3 below. *)
let add_dbls2 l =
List.fold_left
(fun acc a -> (a*2)::a::acc)
[]
l
|> List.rev
(* Fastest but unsafe - stack overflow exception possible if 'l' is large - fold_right is not tail-recursive. *)
let add_dbls3 l =
List.fold_right
(fun a acc -> a::(a*2)::acc)
l
[]
It's should be simple to see that List.map always returns a list of the same length as the input list. But you want a list that's twice as long. So List.map cannot work for you.
You can solve this using List.fold_left or List.fold_right. If you're still having trouble after you switch to using a fold, you could update your question with the new information.
Update
The type of your fold function (a left fold) is this:
('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
So, the folded function takes an accumulated answer and an element of the list, and it returns a new accumulated answer.
Your folded function is like this:
fun a b -> a::b::(b*2)
It attempts to use the :: operator to add new elements to the end of the accumulated list. But that's not what the :: operator does. It adds an element to the beginning of a list.
There's no particularly nice way to add an element to the end of a list. This is intentional, because it's a slow operation.
When using a left fold, you need to reconcile yourself to building up the result in reverse order and possibly reversing it at the end. Or you can use a right fold (which is generally not tail recursive).
I need to break a list like [1;2;3;4;5] into [[1;2]; [3;4]; [5]] in OCaml.
I wrote the following function but it is giving me an error (Error: This expression has type 'a list but an expression was expected of type 'a The type variable 'a occurs inside 'a list)
let rec getNewList l =
match l with
[] -> failwith "empty list"
| [x] -> [x]
| x::(y::_ as t) -> [x;y] :: getNewList t;;
What am I missing? how can I fix it?
You want a function of type 'a list -> 'a list list. However, the second branch of your match returns something of type 'a list.
As a side comment, you shouldn't consider it an error if the input is an empty list. There's a perfectly natural answer for this case. Otherwise you'll have a lot of extra trouble writing your function.
You're not far from a solution. Three things :
if the list is empty, you definitely want your result to be the empty list
second case should be [x] -> [[x]]
for the main case, how many times should y appear in your result ?