Haskell, creating a binary search tree from a list - haskell

Can someone tell me why this code isn't producing what I want.
data BST = MakeNode BST String BST
| Empty
add :: String -> BST -> BST
add new Empty = (MakeNode Empty new Empty)
add string tree#(MakeNode left value right)
| string > value = MakeNode left value (add string right)
| string < value = MakeNode (add string left) value right
| otherwise = tree
output
"John"
"Doug"
"Charlie"
"Alice"
listToBST :: [String] -> BST
listToBST = foldr add Empty

If we create and function which takes a BST and returns a list in sorted order, modelled after sort . nub, then your Tree is fine as quickcheck tells us. QuickCheck is very easy to use.
import Data.List
import Test.QuickCheck
data BST = MakeNode BST String BST
| Empty
deriving (Show)
add :: String -> BST -> BST
add new Empty = (MakeNode Empty new Empty)
add string tree#(MakeNode left value right)
| string > value = MakeNode left value (add string right)
| string < value = MakeNode (add string left) value right
| otherwise = tree
test = ["alice", "blup", "test", "aa"]
manual_test = inorder (foldr add Empty test) == sort (nub test)
prop_inorder = property inorder_test
where inorder_test :: [String] -> Bool
inorder_test xs = inorder (foldr add Empty xs) == sort (nub xs)
-- return sorted nodes
inorder :: BST -> [String]
inorder (Empty) = []
inorder (MakeNode l x r) = inorder l ++ (x : inorder r)
Just load ghci and then run quickCheck prop_inorder.
Other useful functions are:
reverseOrder :: BST -> [String]
reverseOrder Empty = []
reverseOrder (MakeNode l x r) = reverseOrder r ++ (x : reverseOrder r)
asList :: BST -> [String]
asList Empty = []
asList (MakeNode l x r) = x : (asList l ++ asList r)
And also think about making your tree more general by parameterizing over a:
data BST a = Empty | MakeNode (BST a) a (BST a)
You can make it than an instance of Functor, Monad, Foldable and all kind of handy typeclasses.

I tried it and it seems ok to me. It could help if you gave an example of an input that it doesn't work for.
I think the problem may be that string comparison does not work the way you expect ("123" < "7" because "1" < "7"). If I'm right, you might want to use Ints instead of Strings or even better, the class Ord of all the types that can be ordered using (<).

Related

Avoiding conflicting entries in Haskell associative list

I have the following associative list:
myList :: [(myConcept, String)]
myList = [
(myInput, "get_input"),
(myOutput, "get_output"),
(myValues, "get_values")]
-- | Data type
data myConcept = myInput | myOutput | myValues deriving Eq
I want to ensure that the list does not have any conflicting entries if entries are added. How can this be done? Is it possible have the list Map myConcept String to avoid conflicting entries?
Edit:
I can use the following function to prevent conflicting keys, but I would also like to prevent conflicting values.
addOrReplace :: Eq k => k -> v -> [(k, v)] -> [(k, v)]
addOrReplace key value list = (key,value):(filter ((key /=).fst) list)
I understand recursively checking a list, but how do I check the the value from a pair in an associative list?
checkValue :: Eq v => v -> [(k, v)] -> Bool
checkValue :: value [] = False
checkValue :: value [x] = check value of this entry?
checkValue :: value [x:xs]
| check value of this entry?
| otherwise = checkValue value xs
The other issue with the above is that with an [x:xs] it will return the False and not check the rest of the list. How can I add an if condition where "if false, keep checking the list"?
import qualified Data.Map as MAP
import Data.Maybe
import qualified Data.Bimap as BIMAP
data MyConcept = MyInput | MyOutput | MyValues deriving Eq
myList :: [(MyConcept, String)]
myList = [
(MyInput, "get_input"),
(MyOutput, "get_output"),
(MyValues, "get_values")]
To Start of: your fixed checkValue function:
checkValue :: Eq v => v -> [(k, v)] -> Bool
checkValue str [] = False
checkValue str ((t,v):xs)
| str == v = True
| otherwise = checkValue str xs
The generall question you have to ask yourself: should entrys be unique in respective to MyConcept:
(a) schould [(MyInput, "value1"), (MyInput, "value2")] be allowed?
Allso I assume:
(b) MyValues is the only identifier which can hold actual values
-> otherwise it wouldn't make sense to only check on values (= the String part) alone...
Option 1.1: Map
assuming (a) isn't allowed:
-- additionally needed:
instance Ord MyConcept where
compare m1 m2
| m1 == m2 = EQ
| otherwise = LT -- not good but practical
type List_Map1 = MAP.Map MyConcept (MyConcept, String)
add1 :: String -> List_Map1 -> List_Map1
add1 str list = if isNothing value
then MAP.insert MyValues (MyValues, str) list
else error "insert here your prefered runtime error message"
where
value = MAP.lookup MyValues list
Option 1.2: Map
assuming (a) is allowed:
type List_Map2 = MAP.Map String (MyConcept, String)
add2 :: String -> List_Map2 -> List_Map2
add2 str list = if isNothing value
then MAP.insert str (MyValues, str) list
else error ""
where
value = MAP.lookup str list
Option 2: BiMap
type List_Bimap = BIMAP.Bimap MyConcept (MyConcept, String)
add3 :: String -> List_Bimap -> List_Bimap
add3 str list
| isNothing value = BIMAP.insert MyValues (MyValues, str) list
| str == snd (fromJust value) = error "insert here your prefered runtime error message"
-- Change next line to allow (a)
| otherwise = error "insert here your prefered runtime error message"
where
value :: Maybe (MyConcept, String)
value = BIMAP.lookup MyValues list
finally if you prefere simple lists as outputs:
list1 :: String -> List_Map1 -> [(MyConcept, String)]
list1 s l = map snd $ MAP.toList $ add1 s l
list2 :: String -> List_Map2 -> [(MyConcept, String)]
list2 s l = map snd $ MAP.toList $ add2 s l
list3 :: String -> List_Bimap -> [(MyConcept, String)]
list3 s l = map snd $ BIMAP.toList $ add3 s l
I suspect a Bimap would get you almost everything you want. You might have to write a small wrapper to throw a runtime error (instead of overwriting) on duplicate entries, but it shouldn't be too hard.

Finding element in a binary tree

Assume I have a binary tree:
data Bst a = Empty | Node (Bst a) a (Bst a)
I have to write a function that searches for a value and returns the number of its children. If there is no node with this value, it returns -1. I was trying to write both BFS and DFS, and I failed with both.
Pattern matching is your friend. Your Bst can either be Empty or a Node, so at the toplevel, your search function will be
search Empty = ...
search (Node left x right) = ...
Can an Empty tree possibly contain the target value? With a Node the target value, if present, will be either the node value (x above), in the left subtree, in the right subtree—or perhaps some combination of these.
By “return[ing] the number of its children,” I assume you mean the total number of descendants of the Bst rooted at a Node whose value is the target, which is an interesting combination of problems. You will want another function, say numChildren, whose definition uses pattern matching as above. Considerations:
How many descendants does an Empty tree have?
In the Node case, x doesn’t count because you want descendants. If only you had a function to count the number of children in the left and right subtrees …
Here is a way to do this. Breath-first search can actually be a bit tricky to implement and this solution (findBFS) has aweful complexity (appending to the list is O(n)) but you'll get the gist.
First I have decided to split out the finding functions to return the tree where the node element matches. That simplifies splitting out the counting function. Also, it is easier to return the number of elements than the number of descendants and return -1 in case not found, so the numDesc functions rely on the numElements function.
data Tree a = Empty
| Node a (Tree a) (Tree a)
numElements :: Tree a -> Int
numElements Empty = 0
numElements (Node _ l r) = 1 + numElements l + numElements r
findDFS :: Eq a => a -> Tree a -> Tree a
findDFS _ Empty = Empty
findDFS x node#(Node y l r) | x == y = node
| otherwise = case findDFS x l of
node'#(Node _ _ _) -> node'
Empty -> findDFS x r
findBFS :: Eq a => a -> [Tree a] -> Tree a
findBFS x [] = Empty
findBFS x ((Empty):ts) = findBFS x ts
findBFS x (node#(Node y _ _):ts) | x == y = node
findBFS x ((Node _ l r):ts) = findBFS x (ts ++ [l,r])
numDescDFS :: Eq a => a -> Tree a -> Int
numDescDFS x t = numElements (findDFS x t) - 1
numDescBFS :: Eq a => a -> Tree a -> Int
numDescBFS x t = numElements (findBFS x [t]) - 1

Searching rose tree in Haskell

I'm trying to write a function searching for a given element in a rose tree and returning it's location.
It may be clearer when I show you what I already got:
Given a tree with a definition:
data Tree text = Node value
[Tree value]
for example:
test = Node "1" [
Node "11" [
Node "111" [],
Node "112" [
Node "1121" [], Node "1122" [], Node "1123" []
]
],
Node "12" []
]
1
11 12
111 112
1121 1122 1123
I'm looking for a function search:
search :: String -> Tree String -> [Integer]
search 1123 test -> should return [1,2,3]
- first subtree of 1=11 -> 2nd subtree of 11=112, 3rd subtree of 112=1123
I know how to iterate through tree,
display (Node v xs) = v ++ concatMap display xs
But have no idea how can I assign integer value to every element of subtrees array and additionally pass it recursively from upper to lower parts of the tree.
Can you guys direct me where/how to look for a solution? I'm very new to Haskell..
The easiest way is to let the function return the list of all paths to a node with the desired data (there should only ever be at most one in the tree, I suppose, but that doesn't matter) first, and then use the first of these:
searchList :: (Eq a) => a -> Tree a -> [[Integer]]
searchList val (Node dat subs)
| val == dat = [[]] -- empty path
| otherwise = concat [map (c:) (searchList val t) | (c,t) <- zip [1 .. ] subs]
search :: Eq a => a -> Tree a -> [Integer]
search val t = case searchList val t of
(p:_) -> p
_ -> error "Value not found"
If Daniel Wagner's suspicion is correct and your trees are tries, you can search more efficiently, but the principle remains the same, however, since we now know that we either have one node with the desired data or none, the result is more appropriately a Maybe [Integer]:
import Data.List (isPrefixOf)
import Control.Monad -- for the MonadPlus instance of Maybe
searchTrie :: String -> Tree String -> Maybe [Integer]
searchTrie target (Node val subs)
| val == target = Just []
| val `isPrefixOf` target = case dropWhile smaller (zip [1 .. ] subs) of
((c,t):_) -> fmap (c:) $ searchTrie target t
_ -> Nothing
| otherwise = Nothing
where
smaller (_,Node v _) = v < take (length v) target

Retrieve strings from Matrix

I'm stuck with my homework task, somebody help, please..
Here is the task:
Find all possible partitions of string into words of some dictionary
And here is how I'm trying to do it:
I use dynamical programming concept to fill matrix and then I'm stuck with how to retrieve data from it
-- Task5_2
retrieve :: [[Int]] -> [String] -> Int -> Int -> Int -> [[String]]
retrieve matrix dict i j size
| i >= size || j >= size = []
| index /= 0 = [(dict !! index)]:(retrieve matrix dict (i + sizeOfWord) (i + sizeOfWord) size) ++ retrieve matrix dict i (next matrix i j) size
where index = (matrix !! i !! j) - 1; sizeOfWord = length (dict !! index)
next matrix i j
| j >= (length matrix) = j
| matrix !! i !! j > 0 = j
| otherwise = next matrix i (j + 1)
getPartitionMatrix :: String -> [String] -> [[Int]]
getPartitionMatrix text dict = [[ indiceOfWord (getWord text i j) dict 1 | j <- [1..(length text)]] | i <- [1..(length text)]]
--------------------------
getWord :: String -> Int -> Int -> String
getWord text from to = map fst $ filter (\a -> (snd a) >= from && (snd a) <= to) $ zip text [1..]
indiceOfWord :: String -> [String] -> Int -> Int
indiceOfWord _ [] _ = 0
indiceOfWord word (x:xs) n
| word == x = n
| otherwise = indiceOfWord word xs (n + 1)
-- TESTS
dictionary = ["la", "a", "laa", "l"]
string = "laa"
matr = getPartitionMatrix string dictionary
test = retrieve matr dictionary 0 0 (length string)
Here is a code that do what you ask for. It doesn't work exactly like your solution but should work as fast if (and only if) both our dictionary lookup were improved to use tries as would be reasonable. As it is I think it may be a bit faster than your solution :
module Partitions (partitions) where
import Data.Array
import Data.List
data Branches a = Empty | B [([a],Branches a)] deriving (Show)
isEmpty Empty = True
isEmpty _ = False
flatten :: Branches a -> [ [ [a] ] ]
flatten Empty = []
flatten (B []) = [[]]
flatten (B ps) = concatMap (\(word, bs) -> ...) ps
type Dictionary a = [[a]]
partitions :: (Ord a) => Dictionary a -> [a] -> [ [ [a] ] ]
partitions dict xs = flatten (parts ! 0)
where
parts = listArray (0,length xs) $ zipWith (\i ys -> starting i ys) [0..] (tails xs)
starting _ [] = B []
starting i ys
| null words = ...
| otherwise = ...
where
words = filter (`isPrefixOf` ys) $ dict
go word = (word, parts ! (i + length word))
It works like this : At each position of the string, it search all possible words starting from there in the dictionary and evaluates to a Branches, that is either a dead-end (Empty) or a list of pairs of a word and all possible continuations after it, discarding those words that can't be continued.
Dynamic programming enter the picture to record every possibilities starting from a given index in a lazy array. Note that the knot is tied : we compute parts by using starting, which uses parts to lookup which continuations are possible from a given index. This only works because we only lookup indices after the one starting is computing and starting don't use parts for the last index.
To retrieve the list of partitions from this Branches datatype is analogous to the listing of all path in a tree.
EDIT : I removed some crucial parts of the solution in order to let the questioner search for himself. Though that shouldn't be too hard to complete with some thinking. I'll probably put them back with a somewhat cleaned up version later.

haskell binary search tree

module Main where
import Data.List
import Data.Function
type Raw = (String, String)
icards = [("the", "le"),("savage", "violent"),("work", "travail"),
("wild", "sauvage"),("chance", "occasion"),("than a", "qu'un")]
data Entry = Entry {wrd, def :: String, len :: Int, phr :: Bool}
deriving Show
-- French-to-English, search-tree section
entries' :: [Entry]
entries' = map (\(x, y) -> Entry y x (length y) (' ' `elem` y)) icards
data Tree a = Empty | Tree a (Tree a) (Tree a)
tree :: Tree Entry
tree = build entries'
build :: [Entry] -> Tree Entry
build [] = Empty
build (e:es) = ins e (build es)
ins :: Entry -> Tree Entry -> Tree Entry
...
find :: Tree Entry -> Word -> String
...
translate' :: String -> String
translate' = unwords . (map (find tree)) . words
so i'm trying to design function ins and find but i am not sure where to start.any ideas?
I have no idea by which criteria the tree should be sorted, so I use just wrd. Then it would look like:
ins :: Entry -> Tree Entry -> Tree Entry
ins entry Empty = Tree entry Empty Empty
ins entry#(Entry w _ _ _) (Tree current#(Entry w1 _ _ _) left right)
| w == w1 = error "duplicate entry"
| w < w1 = Tree current (ins entry left) right
| otherwise = Tree current left (ins entry right)
How to get there?
As always when using recursion, you need a base case. Here it is very simple: If the tree is empty, just replace it by a node containing your data. There are no children for the new node, so we use Empty.
The case if you have a full node looks more difficult, but this is just due to pattern matching, the idea is very simple: If the entry is "smaller" you need to replace the left child with a version that contains the entry, if it is "bigger" you need to replace the right child.
If both node and entry have the same "size" you have three options: keep the old node, replace it by the new one (keeping the children) or throw an error (which seems the cleanest solution, so I did it here).
A simple generalization of Landei's answer:
ins :: Ord a => a -> Tree a -> Tree a
ins x Empty = Tree x Empty Empty
ins x (Tree x' l r) = case compare x x' of
EQ -> undefined
LT -> Tree x' (ins x l) r
GT -> Tree x' l (ins x r)
For this to work on Tree Entry, you will need to define an instance of Ord for Entry.

Resources