(** {1 Basic definitions} *) type ('a, 'b) sum = Left of 'a | Right of 'b (** An element of [('a, 'b) sum] is either a ['a] or a ['b] *) type 'a stream = Stream of (unit -> ('a * 'a stream) option) (** (possibly infinite) streams of values *) (** you have to implement the functions below; this may not be very useful for the rest of the project, but consider this a warmup exercize *) val nil : 'a stream val cons : 'a -> 'a stream -> 'a stream (** lazy cons *) val lcons : 'a -> (unit -> 'a stream) -> 'a stream val get : 'a stream -> ('a * 'a stream) option val take : 'a stream -> int -> 'a list val number_stream : int stream (** the infinite stream [0,1,2,3...] *) val stream_of_list : 'a list -> 'a stream (** {1 First part: fair search} The goal of the module Logic1, whose signature is below, is to represent search problems: an OCaml expression of type ['a search] represents a description of values of type ['a] that we would like to search for. For example, with the combinators of this module you can define a value of type [(int * int) search] that searches for a couple of prime numbers [(p,q)] such that [q = p+2] or, if you want, that represent all such couples. In the general case, such search problems may have zero, several or even an infinite number of solutions. You will have to implement a function {[ solve : int -> 'a search -> 'a list ]} such that [solve n prob] returns a list of [n] solutions to the search problem [prob], or less if there do not exist so enough solutions. Solutions may be returned in any order, but you must be ale to provide all possible solutions (if there is a finite number of solutions). *) module Logic1 : sig type 'a search (** the type of search descriptions *) val solve : int -> 'a search -> 'a list (** [solve n prob] returns [n] solutions to the search problem [prob], or less if there aren't so many solutions *) val stream : 'a stream -> 'a search (** a stream can be seen as a search problems whose solutions are all the elements present in the stream *) val return : 'a -> 'a search (** a single value also defines a search problem (which has exactly this value as solution *) val fail : 'a search (** the search problem with no solution *) val map : ('a -> 'b) -> 'a search -> 'b search (** the solutions of [map f prob] are all the [f x] such that [x] is a solution of [prob]. *) val sum : 'a search -> 'b search -> ('a, 'b) sum search (** the solutions of [sum pa pb] are all the solutions of problem [pa], and all the solutions of problem [pb] *) val prod : 'a search -> 'b search -> ('a * 'b) search val guard : ('a -> bool) -> 'a search -> 'a search (** the solutions of [guard condition prob] are the solutions of [prob] that also satisfy [condition]. *) end (** Evaluation The following code should work: {[ let () = let open Logic1 in let number = stream number_stream in let posnum = guard (fun n -> n > 0) number in let pytha = (* we search for triples pythagorean triples (a, b, c): a² + b² = c² to avoid duplication of solutions, we also request (a < b) *) let ab = prod posnum posnum |> guard (fun (a,b) -> a < b) in prod ab posnum |> guard (fun ((a,b),c) -> a*a+b*b=c*c) in solve 10 pytha |> List.iter (fun ((a,b),c) -> Printf.printf "%d² + %d² = %d²\n" a b c) ]} A difficulty with this exercize is that [posnumber] has an infinite number of solutions. If you haven't defined [prod] carefully enough, this program may loop without returning anything, despite having simple solutions. PS: (|>) and (@@) are infix operators defined in OCaml 4.01 as let (@@) f x = f x let (|>) x f = f x If you have an older OCaml version, just define them at the top of your file. *) (** {1 Second part: distribution probabilities} *)