I'm learning F# and I'm trying to solve this exercise but my solution feels really... heavy and I suspect that there might an easier way of solving this task.
The task goes like that:
Declare two mutually recursive functions:
insertChildOf: Name -> FamilyTree -> FamilyTree -> FamilyTree option
insertChildOfInList: Name -> FamilyTree -> Children -> Children option
The value of insertChildOf n c t = Some t when t is the family tree obtained from t by insertion of c as a child of the person with name n. The value is None if such an insertion is not possible. Similarly, the value of insertChildOfInList n c cs = Some cs when cs is the list of children obtained from cs by inserting c as a child of a person named n in one of the children in cs. The value is None if such an insertion is not possible. Note that the person named n may occur anywhere in the family tree.
The type for the tree:
type Name = string;;
type Sex =
| M // male
| F // female
type YearOfBirth = int;;
type FamilyTree = P of Name * Sex * YearOfBirth * Children
and Children = FamilyTree list;;
You can assume that the tree has the following proprieties.
All children are younger than their parent.
The children are arranged form the oldest to the youngest.
Make sure that the tree you return also has those parameters.
My code:
let rec insertChildOf n c t =
let (P (_, _, yobi, _)) = c
match t with
| (P (name, sex, yob, children)) when n = name && yob < yobi ->
match insertHere c children -infinity with
| Some a -> Some ( P (name, sex, yob, a ))
| None -> None
| (P (name, _, yob, children)) when n = name && yob > yobi -> None
| (P (n, s, y, children)) ->
match insertChildOfInList n c children with
| Some a -> Some ( P (n, s, y, a ))
| None -> None
and insertChildOfInList n c cs =
match cs with
| h::t ->
match insertChildOf n c h with
| Some h2 ->
match insertChildOfInList n c t with
| Some a -> Some (h2::a)
| None -> None
| None -> None
| [] -> Some []
and insertHere t cs acc =
match cs with
| [] -> Some [t]
| h::tail ->
let (P (_, _, yob, _)) = t
let (P (_, _, yob2, _)) = h
if acc < yob && yob < yob2 then Some (t::h::tail)
else if yob = yob2 then None
else // h::(insertHere t tail (float yob2))
match insertHere t tail (float yob2) with
| Some a -> Some (h::a )
| None -> None
Once again, my question is: Can I do it in any simpler way?
Also, is there any way to return None if we didn't find FamilyTree with the right name? The one way I can think of is making all the functions return one more extra value called (found) which would signal if the node with the correct name was found, and creating a wrapper that would check the value of that variable and return None if the found was false.
To be honest, it isnt really any shorter than yours.
I've not used any 'fancy' library methods (e.g. things like sortby, or Option.map as you havent either)
I can't guarentee that its completely correct
I've written it as explicit lambda functions to make the types explicit - this isnt normal.
I didnt use the tuple syntax you need, because i find tuple syntax clumsy in this example.
I've put some test cases at the end.
type Name = string
type Sex =
| M // male
| F // female
type YearOfBirth = int
type FamilyTree =
{ name: string
sex: Sex
yearOfBirth: YearOfBirth
children: Children
}
and Children = FamilyTree list
let makeFamilyTree name sex yearOfBirth children =
{ name = name
sex = sex
yearOfBirth = yearOfBirth
children = children
}
let rec addChild : FamilyTree -> Children -> Children =
fun newChild children ->
match children with
| [] ->
[newChild]
| eldest :: tail when eldest.yearOfBirth < newChild.yearOfBirth ->
newChild :: eldest :: tail
| eldest :: tail ->
eldest :: addChild newChild tail
let rec insertChildOf: Name -> FamilyTree -> FamilyTree -> FamilyTree option =
fun name childTree tree ->
let childrenMaybe =
if name = tree.name && tree.yearOfBirth < childTree.yearOfBirth then
addChild childTree tree.children
|> Some
else
insertChildOfInList name childTree tree.children
match childrenMaybe with
| Some children ->
Some { tree with children = children }
| None ->
None
and insertChildOfInList: Name -> FamilyTree -> Children -> Children option =
fun name childTree children ->
match children with
| [] ->
None
| eldest :: younger ->
match insertChildOf name childTree eldest with
| Some eldest' ->
Some (eldest' :: younger)
| _ ->
None
let jon =
{ name = "Jon"
sex = Sex.M
yearOfBirth = 1100
children = []
}
let jon2 =
insertChildOf
"Jon"
(makeFamilyTree
"Dave"
Sex.M
1120
[])
jon
let jon3 =
insertChildOf
"Dave"
(makeFamilyTree
"Mary"
Sex.F
1140
[])
jon2.Value
let jon4 =
insertChildOf
"Dave"
(makeFamilyTree
"Elizabeth"
Sex.F
1141
[])
jon3.Value
let jon5 =
insertChildOf
"Dave"
(makeFamilyTree
"George"
Sex.F
1142
[])
jon4.Value
Related
let rec contains (x: int list)(y: int) : bool =
begin match x with
| [] -> false
| [y] -> true
| hd::tail -> (hd = y) && (contains tail y)
end
I'm not sure where I'm going wrong in my pattern matching but for any non-empty list I input, I keep getting "true" as my return type, when I want it to return true only if the input int exists in the list.
You have several problems.
The first is you use pattern matching to check if the list is exactly [y].
This is not how it works, it will actually match any list with exactly one element.
If you want to state equalities like that you can use when clauses.
let rec contains (l : int list) (y : int) : bool =
begin match l with
| [] -> false
| [z] when z = y -> true
| [z] -> false
| hd :: tl -> hd = y && contains tl y
end
The first [z] when z = y will trigger on a list containing exactly your y.
The second clause [z] will trigger on the rest.
Then, there is the problem of your last case: y belongs to hd :: tl if it is hd or if it belongs in tl. You used and, so that couldn't be right.
This gives us:
let rec contains (l : int list) (y : int) : bool =
begin match l with
| [] -> false
| [z] when z = y -> true
| [z] -> false
| hd :: tl -> hd = y || contains tl y
end
Of course this can even be simplified.
let rec contains (l : int list) (y : int) : bool =
begin match l with
| [] -> false
| hd :: tl -> hd = y || contains tl y
end
Indeed there is no need to make a special case of the list with one element.
[y] is the same as y :: [].
So to sum it up, if the element is in the head you got it, otherwise you go look in the tail, and so on until you reach the empty list which means you didn't find it.
open System
open System.Collections.Generic
type Node<'a>(expr:'a, symbol:int) =
member x.Expression = expr
member x.Symbol = symbol
override x.GetHashCode() = symbol
override x.Equals(y) =
match y with
| :? Node<'a> as y -> symbol = y.Symbol
| _ -> failwith "Invalid equality for Node."
interface IComparable with
member x.CompareTo(y) =
match y with
| :? Node<'a> as y -> compare symbol y.Symbol
| _ -> failwith "Invalid comparison for Node."
type Ty =
| Int
| String
| Tuple of Ty list
| Rec of Node<Ty>
| Union of Ty list
type NodeDict<'a> = Dictionary<'a,Node<'a>>
let get_nodify_tag =
let mutable i = 0
fun () -> i <- i+1; i
let nodify (dict: NodeDict<_>) x =
match dict.TryGetValue x with
| true, x -> x
| false, _ ->
let x' = Node(x,get_nodify_tag())
dict.[x] <- x'
x'
let d = Dictionary(HashIdentity.Structural)
let nodify_ty x = nodify d x
let rec int_string_stream =
Union
[
Tuple [Int; Rec (nodify_ty (int_string_stream))]
Tuple [String; Rec (nodify_ty (int_string_stream))]
]
In the above example, the int_string_stream gives a type error, but it neatly illustrates what I want to do. Of course, I want both sides to get tagged with the same symbol in nodify_ty. When I tried changing the Rec type to Node<Lazy<Ty>> I've found that it does not compare them correctly and each sides gets a new symbol which is useless to me.
I am working on a language, and the way I've dealt with storing recursive types up to now is by mapping Rec to an int and then substituting that with the related Ty in a dictionary whenever I need it. Currently, I am in the process of cleaning up the language, and would like to have the Rec case be Node<Ty> rather than an int.
At this point though, I am not sure what else could I try here. Could this be done somehow?
I think you will need to add some form of explicit "delay" to the discriminated union that represents your types. Without an explicit delay, you'll always end up fully evaluating the types and so there is no potential for closing the loop.
Something like this seems to work:
type Ty =
| Int
| String
| Tuple of Ty list
| Rec of Node<Ty>
| Union of Ty list
| Delayed of Lazy<Ty>
// (rest is as before)
let rec int_string_stream = Delayed(Lazy.Create(fun () ->
Union
[
Tuple [Int; Rec (nodify_ty (int_string_stream))]
Tuple [String; Rec (nodify_ty (int_string_stream))]
]))
This will mean that when you pattern match on Ty, you'll always need to check for Delayed, evaluate the lazy value and then pattern match again, but that's probably doable!
I have to create a type tree which would be used to store words, like every node of the tree would hold a letter and the list of the next characters (so words with the same root would share the same "part/branch of the tree). the tree is basically a n-ary one, used as a dictionnary.
All using Caml language
Well, I don't know if it's a homework or not but I'll still answer :
First, we need to define a signature type for letters.
module type LS = sig
type t
val compare : t -> t -> int
end
Then, we need to define our structure :
module Make (L : LS) = struct
module M = Map.Make(L)
type elt = L.t list
type t = { word : bool; branches : t M.t }
let empty = { word = false; branches = M.empty }
let is_empty t = not t.word && M.is_empty t.branches
let rec mem x t =
match x with
| [] -> t.word
| c :: cl -> try mem cl (M.find c t.branches)
with Not_found -> false
let rec add x t =
match x with
| [] -> if t.word then t else { t with word = true }
| c :: cl ->
let b = try M.find c t.branches with Not_found -> empty in
{ t with branches = M.add c (add cl b) t.branches }
end
Now, step by step :
module Make (L : LS) = struct is a functor that will return a new module if we give it a module of type LS as an argument
module M = Map.Make(L)
type elt = L.t list
type t = { word : bool; branches : t M.t }
This is the complex point, once you have it, everything begins clear. We need to represent a node (as you can see in the Wikipedia page of tries). My representation is this : a node is
a truth value stating that this node represent a word (which means that all the letters from the root to this node form a word)
the branches that goes from it. To represent this branches, I need a dictionary and luckily there's a Map functor in OCaml. So, my field branches is a field associating to some letters a trie (which is why I wrote that branches : t M.t). An element is then a list of letters and you'll find out why I chose this type rather than a string.
let empty = { word = false; branches = M.empty } the empty trie is the record with no branches (so, just the root), and this root is not a word (so word = false) (same idea for is_empty)
let rec mem x t =
match x with
| [] -> t.word
| c :: cl -> try mem cl (M.find c t.branches)
with Not_found -> false
Here it becomes interesting. My word being a list of letters, if I want to know if a word is in my trie, I need to make a recursive functions going through this list.
If I reached the point where my list is empty it means that I reached a node where the path from the root to it is composed by all the letters of my word. I just need to know, then, if the value word at this node is true or false.
If I still have at least one letter I need to find the branch corresponding to this letter.
If I find this branch (which will be a trie), I just need to make a recursive call to find the rest of the word (cl) in it
If I don't find it I know that my word doesn't exist in my trie so I can return false.
let rec add x t =
match x with
| [] -> if t.word then t else { t with word = true }
| c :: cl ->
let b = try M.find c t.branches with Not_found -> empty in
{ t with branches = M.add c (add cl b) t.branches }
Same idea. If I want to add a word :
If my list is empty it means that I added all the letters and I've reached the node corresponding to my word. In that case, if word is already true it means that this word was already added, I don't do anything. If word is false I just return the same branch (trie) but with word equal to true.
If my list contains at least a letter c, I find in the current node the branch corresponding to it (try M.find c t.branches with Not_found -> empty) and I there's no such branch, I just return an empty one and then I recursively add the rest of my letters to this branch and add this new branch to the branches of my current node associated to the letter c (if this branch already existed, it will be replaced since I use a dictionary)
Here, we start with the empty trie and we add the word to, top and tea.
In case we don't want to use functors, we can do it this way :
type elt = char list
type t = { word : bool; branches : (char * t) list }
let empty = { word = false; branches = [] }
let is_empty t = not t.word && t.branches = []
let find c l =
let rec aux = function
| [] -> raise Not_found
| (c', t) :: tl when c' = c -> t
| _ :: tl -> aux tl
in aux l
let rec mem x t =
match x with
| [] -> t.word
| c :: cl -> try mem cl (find c t.branches)
with Not_found -> false
let rec add x t =
match x with
| [] -> if t.word then t else { t with word = true }
| c :: cl ->
let b = try find c t.branches with Not_found -> empty in
{ t with branches = (c, (add cl b)) :: t.branches }
type exp =
| CONST of int
| VAR of var
| ADD of exp * exp
| SUB of exp * exp
| ISZERO of exp
| IF of exp * exp * exp
| LET of var * exp * exp
| PROC of var * exp
| CALL of exp * exp
and var = string
type typ = TyInt | TyBool | TyFun of typ * typ | TyVar of tyvar
and tyvar = string
type typ_eqn = (typ * typ) list
module TEnv = struct
type t = var -> typ
let empty = fun _ -> raise (Failure "Type Env is empty")
let extend (x,t) tenv = fun y -> if x = y then t else (tenv y)
let find tenv x = tenv x
end
let rec gen_equations : TEnv.t -> exp -> typ -> typ_eqn
=fun tenv e ty -> match e with
| CONST n -> [(ty, TyInt)]
| VAR x -> [(ty, TEnv.find tenv x)]
| ADD (e1,e2) -> [(ty, TyInt)]#
[gen_equations (tenv, e1, TyInt)]#
[gen_equations (tenv, e2, TyInt)]
Hi, I'm trying to implement the type equation generator that I recently learned in class.
But when I tried implementing the ADD expression using the above method, I get an error saying, "This expression has type ('a -> 'b -> typ_eqn) list, but an expression was expected of type (typ * typ) list."
Isn't appending two or more typ_eqn type lists basically the same thing as (typ * typ) list?
edit:
let rec gen_equations : TEnv.t -> exp -> typ -> typ_eqn
=fun tenv e ty -> match e with
| CONST n -> [(ty, TyInt)]
| VAR x -> [(ty, TEnv.find tenv x)]
| ADD (e1,e2) -> let l1 = [(ty, TyInt)] in
let l2 = gen_equations (tenv, e1, TyInt) in
let l3 = gen_equations (tenv, e2, TyInt) in
l1::l2::l3
I've tried this method too, but this gives me an error message:
"This expression has type (typ * typ) list, but an expression was expected of type (typ * typ)."
Why is this suddenly expecting something different???
In your first version you write [gen_equations (tenv, e1, TyInt)], but gen_equations already returns a list. You might try writing just gen_equations tenv e1 TyInt (note change from uncurried to curried form).
In your second version, you're using :: to join two lists. But :: is for joining an element to a list. You might try l1 # l2 # l3.
Update
In both versions, you're calling gen_equations in uncurried form, but it is defined in curried form. Call like this: gen_equations tenv e1 TyInt.
I am learning Jason Hickey's Introduction to Objective Caml.
There is an exercise like this:
Exercise 4.3 Suppose we have a crypto-system based on the following substitution cipher, where each plain letter is encrypted according to the following table.
Plain | A B C D
--------------------
Encrypted | C A D B
For example, the string BAD would be encrypted as ACB.
Write a function check that, given a plaintext string s1 and a ciphertext string s2, returns true if, and only if, s2 is the ciphertext for s1. Your function should raise an exception if s1 is not a plaintext string. You may wish to refer to the string operations on page 8. How does your code scale as the alphabet gets larger? [emphasis added]
Basically, I wrote two functions with might-be-stupid-naive ways for this exercise.
I would like to ask for advice on my solutions first.
Then I would like to ask for hints for the scaled solution as highlighted in the exercise.
Using if else
let check_cipher_1 s1 s2 =
let len1 = String.length s1 in
let len2 = String.length s2 in
if len1 = len2 then
let rec check pos =
if pos = -1 then
true
else
let sub1 = s1.[pos] in
let sub2 = s2.[pos] in
match sub1 with
| 'A' -> (match sub2 with
|'C' -> check (pos-1)
| _ -> false)
| 'B' -> (match sub2 with
|'A' -> check (pos-1)
| _ -> false)
| 'C' -> (match sub2 with
|'D' -> check (pos-1)
| _ -> false)
| 'D' -> (match sub2 with
|'B' -> check (pos-1)
| _ -> false)
| _ -> false;
in
check (len1-1)
else
false
Using pure match everywhere
let check_cipher_2 s1 s2 =
let len1 = String.length s1 in
let len2 = String.length s2 in
match () with
| () when len1 = len2 ->
let rec check pos =
match pos with
| -1 -> true
| _ ->
let sub1 = s1.[pos] in
let sub2 = s2.[pos] in
(*http://stackoverflow.com/questions/257605/ocaml-match-expression-inside-another-one*)
match sub1 with
| 'A' -> (match sub2 with
|'C' -> check (pos-1)
| _ -> false)
| 'B' -> (match sub2 with
|'A' -> check (pos-1)
| _ -> false)
| 'C' -> (match sub2 with
|'D' -> check (pos-1)
| _ -> false)
| 'D' -> (match sub2 with
|'B' -> check (pos-1)
| _ -> false)
| _ -> false
in
check (len1-1)
| () -> false
Ok. The above two solutions are similar.
I produced these two, because in here http://www.quora.com/OCaml/What-is-the-syntax-for-nested-IF-statements-in-OCaml, some people say that if else is not prefered.
This is essentially the first time I ever wrote a not-that-simple function in my whole life. So I am really hungry for suggestions here.
For exmaple,
how can I improve these solutions?
should I prefer match over if else?
Am I designing the rec or use the rec correctly?
if that in check (len1-1) correct?
Scale it
The exercise asks How does your code scale as the alphabet gets larger?. I really don't have a clue for now. In Java, I would say I will have a map, then for each char in s1, I am looking s2 for the according char and to see whether it is the value in the map.
Any suggestions on this?
Here's a simple solution:
let tr = function
| 'A' -> 'C'
| 'B' -> 'A'
| 'C' -> 'D'
| 'D' -> 'B'
| _ -> failwith "not a plaintext"
let check ~tr s1 s2 = (String.map tr s1) = s2
check ~tr "BAD" "ACD"
you can add more letters by composing with tr. I.e.
let comp c1 c2 x = try (c1 x) with _ -> (c2 x)
let tr2 = comp tr (function | 'X' -> 'Y')
how can I improve these solutions?
You misuse indentation which makes the program much harder to read. Eliminating unnecessary tabs and move check to outer scope for readability:
let check_cipher_1 s1 s2 =
let rec check pos =
if pos = -1 then
true
else
let sub1 = s1.[pos] in
let sub2 = s2.[pos] in
match sub1 with
| 'A' -> (match sub2 with
|'C' -> check (pos-1)
| _ -> false)
| 'B' -> (match sub2 with
|'A' -> check (pos-1)
| _ -> false)
| 'C' -> (match sub2 with
|'D' -> check (pos-1)
| _ -> false)
| 'D' -> (match sub2 with
|'B' -> check (pos-1)
| _ -> false)
| _ -> false in
let len1 = String.length s1 in
let len2 = String.length s2 in
if len1 = len2 then
check (len1-1)
else false
should I prefer match over if else?
It depends on situations. If pattern matching is superficial as you demonstrate in the 2nd function (match () with | () when len1 = len2) then it brings no value compared to a simple if/else construct. If you pattern match on values, it is better than if/else and potentially shorter when you make use of advanced constructs. For example, you can shorten the function by matching on tuples:
let check_cipher_1 s1 s2 =
let rec check pos =
if pos = -1 then
true
else
match s1.[pos], s2.[pos] with
| 'A', 'C' | 'B', 'A'
| 'C', 'D' | 'D', 'B' -> check (pos-1)
| _ -> false in
let len1 = String.length s1 in
let len2 = String.length s2 in
len1 = len2 && check (len1 - 1)
Here we also use Or pattern to group patterns having the same output actions and replace an unnecessary if/else block by &&.
Am I designing the rec or use the rec correctly?
if that in check (len1-1) correct?
Your function looks nice. There's no better way than testing with a few inputs on OCaml top-level.
Scale it
The number of patterns grows linearly with the size of the alphabet. It's pretty nice IMO.
The simplest solution seems to be to just cipher the text and compare the result:
let cipher_char = function
| 'A' -> 'C'
| 'B' -> 'A'
| 'C' -> 'D'
| 'D' -> 'B'
| _ -> failwith "cipher_char"
let cipher = String.map cipher_char
let check_cipher s1 s2 = (cipher s1 = s2)
The cipher_char function scales linearly with the size of the alphabet. To make it a bit more compact and generic you could use a lookup table of some form, e.g.
(* Assume that only letters are needed *)
let cipher_mapping = "CADB"
let cipher_char c =
try cipher_mapping.[Char.code c - Char.code 'A']
with Invalid_argument _ -> failwith "cipher_char"