When I am programming functions on trees in OCaml I always face this recurrent problem : when I get to the leaves of the tree I would like to return nothing but still want my programm to continue.
To be more clear sometimes I have exercises that asked to find a particular node n so I can do the following : (for simplicity I am doing this on binary trees here) :
let rec find_node n tree = match tree with
|Nil -> (* I don't want my program to stop here but then what can I return ?*)
|Node(l, k, r) as t when k =n -> t
|Node(l, _, r) -> find_node n l; find_node n r
I am using the following representation of binary trees :
type b_tree = Nil | Node of b_tree * int * b_tree
So basically I would like my programm to continue running until it finds what it wants, yet since a function in OCaml has only one return type I can't do somehting like :
let rec find_node n tree = match tree with
|Nil -> () (*returning unit type here*)
|Node(l, k, r) as t when k =n -> t
|Node(l, _, r) -> find_node n l; find_node n r
So how can I tell "do nothing" on a pattern case ?
Thank you !
You need to ask yourself: in the third case, how do you know that the first recursion found a result? How do you distinguish this from an unsuccessful recursion and what do you do in either case? Also, what if there is no node meeting your criterion in the entire tree?
So "doing nothing" is not what you want, you somehow need to indicate that nothing was found.
One obvious way to resolve all this is by returning an option, which would yield the following code:
let rec find_node n tree =
match tree with
| Nil -> None
| Node ((_, k, _) as t) when k = n -> Some t
| Node (l, _, r) ->
match find_node n l with
| None -> find_node n r
| some -> some
This has return type (b_tree * int * b_tree) option, describing the node attributes, or being None when no node has been found.
There are two ways to look at this:
1) When you hit Nil in find_node that means that no node was found. You have to return some form of nothing.
1a) You return None, which also means you have to return Some x in the other cases. This is the API flavor with options.
1b) You raise Not_found. This the the API flavor with exceptions.
Some modules follow 1a, other 1b. Some have submodules for the flavors or 2 functions e.g. find_node (exception) and find_node_opt (option). What flavor should you have? That's 50% personal preference and 50% use case. Both are equally valid and both have advantages on the other depending on the use case.
2) Your data type is to blame
I've seen trees defined as
type b_tree = Leaf of int | Node of b_tree * int * b_tree
That way you don't have a Nil case. On the other hand there is no representation of an empty tree then.
It's possible to return nothing in a pattern matching in ocaml, and here is how you can do it:
[] -> ()
thus, for you exemple, it can be done that way:
let rec find_node n tree = match tree with
|Nil -> ()
|Node(l, k, r) as t when k =n -> t
|Node(l, _, r) -> find_node n l; find_node n r
feel free to look at some exemple on this repo:game in ocaml
Related
I need to implement a method to return common elements in two lists as part of an assignment problem:
My idea was to remove duplicates in both lists, concatenate them and return elements that are repeated in the resulting list. I want to define a Boolean function that check for each elements in the list if they appear more than once. My idea was to use List.fold_left with a specific element b in the list and use acc to keep track of the number of times it appears in the list. However, I have an error here:
I have another idea that involves sorting the lists first, But the list could be of any type, hence comparison has to be implemented for new types as well. Or can I just use < to compare any type of values?
Here are the codes that I have so far.
let rec remove (b : 'a) (l : 'a list)=
match l with
| [] -> []
| w::e -> if w=b then remove b e
else w::(remove b e)
let rec removeduplicates (l:'a list)=
match l with
| [] -> []
| w::e -> w::(removeduplicates(remove w e))
let removeduppair (l : 'a list * 'a list)=
let (l1,l2) = l in
(removeduplicates l1, removeduplicates l2)
This expression has a type error:
if x = b then acc + 1
The problem is that doesn't have an else part. In other words, it doesn't say what you want the value to be when x is not equal to b.
You can fix this just by adding an else part.
A little more detail: OCaml allows you to leave off the else part, but only if the then part has unit type. In such a case, the value when the test is false will be the same as when it is true, namely () (the only value of unit type).
I'll start of by saying I'm very new to Haskell, so I haven't learned about things like Monads yet.
In Haskell I'm trying to make a type of tree that has numbers as the leaves and functions as the branches so the whole tree can act kind of like a calculator.
Here's my code so far. Currently instead of having functions as an input I'm just using characters.
data Tree3 = Leaf3 Int | Node3 Char Tree3 Tree3 deriving (Show)
-- I would like to replace this ^ Char somehow with a function.
evaluate :: Tree3 -> Int
evaluate (Leaf3 x) = x
evaluate (Node3 c m n) | c == '+' = evaluate m + evaluate n
| c == '-' = evaluate m - evaluate n
| c == '/' = evaluate m `div` evaluate n
| c == '*' = evaluate m * evaluate n
So my question is can I have an input of a function in the data structure (and what would the type be?)
Sorry for the probably confusing question, but thanks for any advice!
I would recommend writing your tree as:
data Tree = Leaf Int | Node (Int -> Int -> Int) Tree Tree
Note that you won't be able to derive Eq or Show, since Int -> Int doesn't implement either of those typeclasses (and it's impossible impractical to do so).
Then you can write your evaluate function as
evaluate :: Tree -> Int
evaluate (Leaf x) = x
evaluate (Node f l r) = f (evaluate l) (evaluate r)
which is much simpler!
You can make a tree to represent an expression like (1 + 2) * (3 * 4) as
expr :: Tree
expr = Node (*) (Node (+) (Leaf 1) (Leaf 2)) (Node (*) (Leaf 3) (Leaf 4))
Another way that would make it easier to prettier print your tree would be to use almost the same definition you have:
data Tree = Leaf Int | Node String Tree Tree
-- ^ String instead of Char
Then if you have Data.Map imported, you can create a map of functions to look up, but it makes your evaluate function a bit more complex since you introduce the possibility that your function won't be in your map. Luckily Haskell has some really handy tools for handling this elegantly!
import qualified Data.Map as Map
type Tree = Leaf Int | Node String Tree Tree deriving (Eq, Show)
type FuncMap = Map.Map String (Int -> Int -> Int)
evaluate :: FuncMap -> Tree -> Maybe Tree
evaluate funcs (Leaf x) = return x
evaluate funcs (Node funcName left right) = do
-- Use qualified import since there's a Prelude.lookup
f <- Map.lookup funcName funcs
l <- evaluate funcs left
r <- evaluate funcs right
return $ f l r
This will automatically result in Nothing if you try something like
evaluate (Map.fromList [("+", (+))]) (Node "blah" (Leaf 1) (Leaf 2))
since the function "blah" isn't in your FuncMap. Notice how we didn't have to do any explicit error handling of any kind thanks to Maybe's monad instance! If any of the lookups to the function map return Nothing, the whole computation returns Nothing without us having to think about it.
Consider the following definition of trees:
Data Tree a = Empty | Node a (Tree a) (Tree a)
Define the function smallerbigger :: Float -> Tree Float -> ([Float],[Float]) that given a number n and a tree, produces a pair of lists whose elements are smaller and bigger than n.
(the question initially stated that the tree is a search tree, which was done in error).
For a list, you could implement a similar algorithm as
smallerbigger :: Ord a => a -> [a] -> ([a], [a])
smallerbigger x xs = go x xs [] []
where
go y [] lt gt = (lt, gt)
go y (z:zs) lt gt
| z < y = go y zs (z:lt) gt
| z >= y = go y zs lt (z:gt)
The basic shape of the algorithm will remain the same for a Tree, but the biggest difference will be how you recurse. You'll need to recurse down both branches, then once you get the result from each branch concatenate them together along with the result from the current node.
If you get stuck implementing this for a tree, feel free to comment and let me know what problem you're experiencing and include a link to your code in a gist/pastebin/whatever.
Here little set of utilities leading to simple solution. Assuming you need lazy function.
Here your data defition with addition of only show ability for debug
data Tree a = Empty | Node a (Tree a) (Tree a) deriving Show
Next we need to a little utility for easy tree creating. Following code is building a very unbalanced tree that is very similar to original list.
fromList:: [a] -> Tree a
fromList [] = Empty
fromList (x:xs) = Node x Empty (fromList xs)
Simple and obvious representation of tree in list form. Order of elements is preserved.
asList:: Tree a -> [a]
asList Empty = []
asList (Node x left right) = asList left ++ x: asList right
Next we assume we'll need pair of lists that could be lazy regardless of our destination.
We are keeping ability to work with tree that has infinite structure somewhere in the middle, but not at the last or end element.
This definition to walk our tree in opposite direction in lazy manner.
reverseTree:: Tree a -> Tree a
reverseTree Empty = Empty
reverseTree (Node x left right) = Node x (reverseTree right) (reverseTree left)
Next we finally building our procedure. It could create two possible infinite list of elements smaller and bigger than first argument.
smallerbigger::Ord a => a-> Tree a -> ([a],[a])
smallerbigger p t = (takeWhile (<p) $ asList t, takeWhile (>p) $ asList $ reverseTree t)
main = let t = fromList [1..10]
in do
print t
print $ smallerbigger 7 t
But in other hand we may want to preserve order in second list, while we are sure that we never hit bottom building first list. So we could drop elements that are equal to target separator and just span out list at it.
smallerbigger p = span (<p) . filter(/=p) . asList
Thanks for all the help and suggestions.
I managed to find a different solution:
smallerbigger :: Ord a => a -> Tree a -> ([a], [a])
smallerbigger n (Node r e d) =
let (e1,e2) = smallerbigger n e
(d1,d2) = smallerbigger n d
in if r>n then ( e1++d1, r:(e2++d2))
else if r<n then (r:(e1++d1), e2++d2 )
else ( e1++d1, e2++d2 )
Consider the following type to represent trees:
data Tree a = Empty
| Leaf a
| Fork (Tree a) (Tree a)
I need help definig the function removeRandom' :: Tree a -> IO (Tree a) that receives a tree with at least a leaf and returns the result of removing a random leaf from the tree (replacing it with Empty). The exercise had a suggestion: use the function randomRIO :: Random a => (a,a) -> IO a to generate the order of the element to remove
EDIT: trying method 2 of user Thomas
removeRandom' :: Tree a -> IO (Tree a)
removeRandom' t = let lengthTree = numbelems t
in do x <- randomRIO (0,lengthTree -1)
return (remove x t)
numbelems :: Tree a -> Int
numbelems Empty = 0
numbelems Leaf x = 1
numbelems Fork l r = (numbelems l) + (numbelems r)
remove :: Int -> Tree a -> Tree a
remove _ (Leaf x) = Empty
remove n (Fork l r) = let lengthLeft = numbelems l
in if (n>lengthLeft) then Fork l (remove (n-lengthLeft r)
else Fork (remove n l) r
There are 2 ways to approach this problem
Convert to a list, remove the element, and convert back to a tree.
Pros: Simple to implement, you already have toList, all you need is fromList, and you can implement your solution simply as
removeAt :: Int -> [a] -> [a]
removeAt n as = a ++ tail s where (a, s) = splitAt n
removeRandom' tree = do
element <- randomRIO (0, length tree)
return $ fromList $ removeAt element $ toList tree
Cons: This method is not "True" to the problem statement removing a random leaf from the tree (replacing it with Empty) and will likely give you a brand new tree with no Empty values in it. I have only provided this as an option in an attempt to show where your toList method ends up.
Descend into the tree, until you hit the element to be removed, then rebuild the tree on the way back up
Pros: The meat of the algorithm is "Pure" as in, does not touch IO. You only actually need IO for a moment within removeRandom'. You can likely write a solution that looks a bit like this (interesting parts left blank ;).
removeAt :: Int -> Tree a -> Tree a
removeAt n tree = walk 0 tree
where
walk i Empty = ...
walk i (Fork l r) = ...
walk i l#(Leaf _)
| i == n = ...
| otherwise = ...
removeRandom' tree = do
element <- randomRIO (0, length tree)
return $ removeAt element tree
Cons: More complicated to implement, you need to know how to traverse back "up" a tree, rebuilding in your wake, and you will need to know how to write a recursive function with an accumulator such that you can track your position in the tree.
Either way you decide to go, you will need to write a function length :: Tree a -> Int that counts the number of leaves to use as input to randomRIO (which is an action that simply produces a random value in a given range).
I'm trying to learn Erlang using the Karate Chop Kata. I translated the runit test supplied in the kata to an eunit test and coded up a small function to perform the task at hand.
-module(chop).
-export([chop/2]).
-import(lists).
-include_lib("eunit/include/eunit.hrl").
-ifdef(TEST).
chop_test_() -> [
?_assertMatch(-1, chop(3, [])),
?_assertMatch(-1, chop(3, [1])),
?_assertMatch(0, chop(1, [1])),
....several asserts deleted for brevity...
].
-endif.
chop(N,L) -> chop(N,L,0);
chop(_,[]) -> -1.
chop(_, [],_) -> -1;
chop(N, L, M) ->
MidIndex = length(L) div 2,
MidPoint = lists:nth(MidIndex,L),
{Left,Right} = lists:split(MidIndex,L),
case MidPoint of
_ when MidPoint < N -> chop(N,Right,M+MidIndex);
_ when MidPoint =:= N -> M+MidIndex;
_ when MidPoint > N -> chop(N,Left,M)
end.
Compiles ok.Running the test however gives, (amongst others) the following failure:
::error:badarg
in function erlang:length/1
called as length(1)
in call from chop:chop/3
I've tried different permutations of declaring chop(N,[L],M) .... and using length([L]) but have not been able to resolve this issue. Any suggestions are welcome.
ps. As you might have guessed I'm a nube when it comes to Erlang.
So I'm pressed for time at the moment, but the first problem I see is that
chop(N,L) -> chop(N,L,0);
chop(_,[]) -> -1.
is wrong because chop(N,L) will always match. reverse the clauses and see where that gets you.
Beyond that, in the case of the 1 element list, nth(0, [1]) will fail. I feel like these lists are probably 1-indexed.
As most significant thing to learn you should realize, that using binary search for lists in erlang is wrong idea, because lists:nth/2 is not O(1) but O(N) operation. Try list_to_tuple/1 and than do it on tuple. It is much more worth work.
It can also be worth to try it on array module.
The function erlang:length/1 returns the length of a list.
You called length(1) and 1 isn't a list.
length([1]) would return 1
length([1,2,3,4[) would return 4
etc, etc...
It appears that combining the remarks from Ben Hughes solves the problem. Just for completeness I'm pasting the tests-passing implementation of my binary search below.
chop(_,[]) -> -1;
chop(N,L) ->
Array = array:from_list(L),
chop(N,Array, 0, array:size(Array)-1).
chop(N, L, K, K) ->
Element = array:get(K,L),
if
Element == N -> K;
true -> -1
end;
chop(_, _, K, M) when M < K -> -1;
chop(N, L, K, M) ->
MidIndex = K + ((M - K) div 2),
MidPoint = array:get(MidIndex,L),
case MidPoint of
N -> MidIndex;
_ when MidPoint < N -> chop(N,L,MidIndex+1,M);
_ -> chop(N,L,K,MidIndex-1)
end.