Changing a graph to list of nodes in Haskell - haskell

I have these data types :
data Node a = Node
{ label :: a,
adjacent :: [(a,Int)] } deriving Show
data Network a = Graph [Node a] deriving Show
I want to turn a graph to a list of nodes. For example I want to turn this :
Graph [ ( Node 'a' [ ( 'b' , 3 ) , ( 'c' ,2 ) ] ) , ( Node 'b' [ ('c' , 3 ) ] ) , ( Node 'c' [] ) ]
to this :
[ ( Node 'a' [ ( 'b' , 3 ) , ( 'c' ,2 ) ] ) , ( Node 'b' [ ('c' , 3 ) ] ) , ( Node 'c' [] ) ]
I wrote this function and some other variations of it :
deGraph Graph [Node x y] = [Node x y]
but I kept getting erros. Can you tell me how I should change my function?
Thanks.

You're misunderstanding how to pattern match on a list.
foo [x] = x
matches a list of a single element and binds that element to x.
Since you want it to match on all lists, you'd do something like
foo xs = xs
so your code should change to
deGraph (Graph nodes) = nodes
-- Notice the fact that I wrapped the constructor
-- in parens
Wrap up:
Just to be explicit, here are the different ways you can match on a list
-- matches on individual elements (this is syntactic sugary goodness)
foo [x, y] = x
-- grabs the head and tail of the list (This is actual deconstructing)
foo (x:rest) = x
-- matches an empty list
foo [] = error "Oh noes"
-- matches everything
foo xs = head xs
Or any combination of the above.

Related

Problem with code:parse error on input `<-' [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
Today I have a new problem with another code in Haskell: I get the following error "parse error on input `<-'". Would someone explain to me what is wrong with the code and how to make it right? Thanks!
f :: (Int,Int) -> (Int,Int) -> Int -> Int -> [[Int]]
f (h, w) (a, b) k l = let x <- [1..w]
y <- [1..h]
zahl1 <- [1..k]
zahl2 <- [1..l]
in [if ((y, x) == (a, b)) then zahl1 else zahl2] ```
The left arrow (<-) is used to assign values inside do notation, like this:
main = do
line <- getLine
print line
The equals sign is used to assign values as part of a let ... in ... expression, like this:
main =
let line = "hello"
in print line
So mechanically you might think to replace <- with =, but that wouldn't work for your case. It looks like you're trying to create a list using a list comprehension, but instead you're creating a list with only one value in it. I think this may be what you're trying to do:
f :: ( Int, Int ) -> ( Int, Int ) -> Int -> Int -> [ [ Int ] ]
f ( h, w ) ( a, b ) k l =
let
zahl1 = [ 1 .. k ]
zahl2 = [ 1 .. l ]
in
[ if ( y, x ) == ( a, b ) then zahl1 else zahl2
| x <- [ 1 .. w ]
, y <- [ 1 .. h ]
]
I wouldn't necessarily recommend this, but as a bit of trivia you can write list comprehensions using do notation:
f ( h, w ) ( a, b ) k l = do
x <- [ 1 .. w ]
y <- [ 1 .. h ]
if ( y, x ) == ( a, b )
then [ 1 .. k ]
else [ 1 .. l ]

Haskell: How to generate all possible combinations of elements, each element from a list, with arbitrary number of lists [duplicate]

This question already has an answer here:
Haskell function :: [Name] -> [[(Name, Bool)]]
(1 answer)
Closed 4 years ago.
Having a list of ["P", "Q", "R" ...] I want to generate all possible list of [(String, Bool)] where on the left is a letter from the first array, and on the right is True or False. For example having ["P", "Q"] I want to obtain
: [[("P",True),("Q",True)],[("P",True),("Q",False)],[("P",False),("Q",True)],[("P",False),("Q",False)]]
I made it for the case where I only have ["P", "Q"] but I need to suport arbitrary number of letters. I tought I can generate for every letter L two pairs in an array like [(L,True),(L,False)] and do that for every letter and make all possible combinations of those arrays with one element from each array, but I don't know how to do it properly.
That's what I did for the list of length 2 of letters
envs :: [String] -> [[(String, Bool)]]
envs predicate = let
env = [(p,b) | p <- predicate, b <- [True, False]]
ps = filter (\(pred,val) -> pred == "P") env
qs = filter (\(pred,val) -> pred == "Q") env
in [[a,b] | a <- ps, b <- qs]
Introduce this function
cartProdn :: [a] -> Int -> [[a]]
cartProdn ls 2 = [[x, y] | x <- ls, y <- ls]
cartProdn ls n = [x : t | x <- ls, t <- cartProdn ls (n - 1)]
This gives all possible combinations of length n of a finite list (n > 1).
Then do
*Main> ls = ["P", "Q", "R"]
*Main> rs = [zip ls c | c <- cartProdn [True, False] (length ls)]
*Main> putStrLn $ unlines $ map show rs
[("P",True),("Q",True),("R",True)]
[("P",True),("Q",True),("R",False)]
[("P",True),("Q",False),("R",True)]
[("P",True),("Q",False),("R",False)]
[("P",False),("Q",True),("R",True)]
[("P",False),("Q",True),("R",False)]
[("P",False),("Q",False),("R",True)]
[("P",False),("Q",False),("R",False)]
note: you might want to write ls = "PQR".

List Comprehension with list of lists

I have problems to understand the following piece of code:
treePositions :: Tree a -> [[Int]]
treePositions (Node _ ts) =
[] : [ (i : is ) | i <- [0..(length ts - 1)],
is <- treePositions (index ts i) ]
This function would calculate any valid paths to a position in the given tree, where for every node the edges are marked with 0..lastOutgoingEdge.
If I understood it right the index function would return the node at Index i in the node list of the tree.
index :: [a] -> Int -> a
index :: [a] -> Int -> a
index [] i = error "invalid index"
index (x:xs) 0 = x
index (x:xs) i = ith xs (i-1)
Now for given trees:
t1 = Node "a" [
Node "b" [
Node "c"[],
Node "d"[]
]
]
t2 = Node "z" []
the function would return:
treePositions t1 == [ [], [0], [0,0], [0,1] ]
treePositions t2 == [ [] ]
What I don't understand is this part:
[] : [ (i : is ) | i <- [0..(length ts - 1)],is <- treePositions (index ts i) ]
My thoughts:
If I have x|x <- [0..10], x < 2. This would translate in "take every x in [0..10] for which x < 2 applies. So if I would take every i in [0..(length ts - 1)], how would this then return lists for a condition?
In your case, the part after the comma is not a condition, but a second generator. Simplified, the notation looks like this:
> [ (a, b) | a <- [1..3], b <- [1..2] ]
> [(1,1),(1,2),(2,1),(2,2),(3,1),(3,2)]
The example compherension above means the following:
go through list [1..3], and for every element of it,
go through list [1..2], and for every element of it,
produce a tuple
Further, a generator can depend on elements of previous generators, e.g.:
> [ (a, b) | a <- [1..3], b <- [1..a] ]
> [(1,1),(2,1),(2,2),(3,1),(3,2),(3,3)]
So in your case:
[ (i : is ) | i <- [0..(length ts - 1)],is <- treePositions (index ts i) ]
the logic is this:
for every i in 0..(length ts - 1),
go through every is in treePositions (index ts i),
and produce i : is as result

Getting rid of a Graph keyword in Haskell

I have this data type :
data Node a = Node
{ label :: a,
adjacent :: [(a,Int)] } deriving (Show, Eq)
data Network a = Graph [Node a] deriving (Show, Eq)
I have a function which turns a Graph to a list of nodes :
deGraph :: ([Node a] -> Network a) -> [Node a] -> [Node a]
deGraph _ x = x
for example :
Main> deGraph Graph [ ( Node 'a' [ ( 'b' , 3 ) , ( 'c' ,2 ) ] ) , ( Node 'b' [ ('c' , 3 ) ] ) , ( Node 'c' [] ) ]
[Node {label = 'a', adjacent = [('b',3),('c',2)]},Node {label = 'b', adjacent = [('c',3)]},Node {label = 'c', adjacent = []}]
But when I use the function inside a function like this :
func1 (Graph x) = deGraph (Graph x)
I get this error :
ERROR "./Network.hs":14 - Type error in application
* Expression : deGraph (Graph x)
Term : Graph x
Type : Network b
* Does not match : [Node a] -> Network a
Can you tell me how can I solve this problem?
Your deGraph function has two arguments and simply returns the second of the two.
You probably want this instead:
deGraph :: Network a -> [Node a]
deGraph (Graph x) = x
The call to deGraph in GHCi works because you forgot to put parentheses around Graph and the following list, so it's also a call with two arguments. In func1, you (correctly) use parentheses, but then get a type error, because you're inconsistent.
Simply make Graph a record, too:
data Network a = Graph { nodes :: [Node a] } deriving (Show, Eq)
Then nodes has type Network a -> [Node a], and can be called like
Main> nodes $ Graph listOfNodes

Haskell Knapsack

I've written an answer to the bounded knapsack problem with one of each item in Scala, and tried transposing it to Haskell with the following result:
knapsack :: [ ( Int, Int ) ] -> [ ( Int, Int ) ] -> Int -> [ ( Int, Int ) ]
knapsack xs [] _ = xs
knapsack xs ys max =
foldr (maxOf) [ ] [ knapsack ( y : xs ) ( filter (y /=) ys ) max | y <- ys
, weightOf( y : xs ) <= max ]
maxOf :: [ ( Int, Int ) ] -> [ ( Int, Int ) ] -> [ ( Int, Int ) ]
maxOf a b = if valueOf a > valueOf b then a else b
valueOf :: [ ( Int, Int ) ] -> Int
valueOf [ ] = 0
valueOf ( x : xs ) = fst x + valueOf xs
weightOf :: [ ( Int, Int ) ] -> Int
weightOf [ ] = 0
weightOf ( x : xs ) = snd x + weightOf xs
I'm not looking for tips on how to clean up the code, just to get it working. To my knowledge it should be doing the following:
For each tuple option (in ys)
if the weight of the current tuple (y) and the running total (xs) combined is less than the capacity
get the optimal knapsack that contains the current tuple and the current total (xs), using the available tuples (in ys) less the current tuple
Finally, get the most valuable of these results and return it
*Edit: * Sorry, forgot to say what's wrong... So it compiles alright, but it gives the wrong answer. For the following inputs, what I expect and what it produces:
knapsack [] [(1,1),(2,2)] 5
Expect: [(1,1),(2,2)]
Produces: [(1,1),(2,2)]
knapsack [] [(1,1),(2,2),(3,3)] 5
Expect: [(2,2),(3,3)]
Produces: []
knapsack [] [(2,1),(3,2),(4,3),(6,4)] 5
Expect: [(2,1),(6,4)]
Produces: []
So I was wondering what could be the cause of the discrepancy?
The solution, thanks to sepp2k:
ks = knapsack []
knapsack :: [ ( Int, Int ) ] -> [ ( Int, Int ) ] -> Int -> [ ( Int, Int ) ]
knapsack xs [] _ = xs
knapsack xs ys max =
foldr (maxOf) [ ] ( xs : [ knapsack ( y : xs ) ( ys #- y ) max
| y <- ys, weightOf( y : xs ) <= max ] )
(#-) :: [ ( Int, Int ) ] -> ( Int, Int ) -> [ ( Int, Int ) ]
[ ] #- _ = [ ]
( x : xs ) #- y = if x == y then xs else x : ( xs #- y )
maxOf :: [ ( Int, Int ) ] -> [ ( Int, Int ) ] -> [ ( Int, Int ) ]
maxOf a b = if valueOf a > valueOf b then a else b
valueOf :: [ ( Int, Int ) ] -> Int
valueOf [ ] = 0
valueOf ( x : xs ) = fst x + valueOf xs
weightOf :: [ ( Int, Int ) ] -> Int
weightOf [ ] = 0
weightOf ( x : xs ) = snd x + weightOf xs
Which returns the expected results, above.
Your first case fires when ys contains. so for knapsack [foo,bar] [] 42, you get back [foo, bar], which is what you want. However it does not fire when ys contains nothing except elements that would put you over the max weight, i.e. knapsack [(x, 20), (y,20)] [(bla, 5)] will return [] and thus discard the previous result. Since this is not what you want you should adjust your cases so that the second case only fires if there's at least one element in ys that's below the max weight.
One way to do that would be to throw out any elements that put you over the max weight when recursing, so that that scenario simply can't happen.
Another way would be to switch the order of the cases and add a guard to the first case that says that ys must contain at least one element that does not put you over the total weight (and adjust the other case to not require ys to be empty).
PS: Another, unrelated problem with your code is that it ignores duplicates. I.e. if you use it on the list [(2,2), (2,2)] it will act as if the list was just [(2,2)] because filter (y /=) ys will throw out all occurrences of y, not just one.
Some improvements on your working version:
import Data.List
import Data.Function(on)
ks = knapsack []
knapsack :: [(Int, Int)] -> [(Int, Int)] -> Int -> [(Int, Int)]
knapsack xs [] _ = xs
knapsack xs ys max =
foldr (maxOf) [] (xs: [knapsack (y:xs) (delete y ys) max
| y <- ys, weightOf(y:xs) <= max ] ) where
weightOf = sum . map snd
maxOf :: [(Int, Int)] -> [(Int, Int)] -> [(Int, Int)]
maxOf a b = maximumBy (compare `on` valueOf) [a,b] where
valueOf = sum . map fst
Might I suggest using a dynamic programming approach? This way of solving 0-1 knapsack problems are almost painfully slow, at least when the amount of variables gets larger than around 20. While it's simple, it's just too ineffective. Here's my shot at it:
import Array
-- creates the dynamic programming table as an array
dynProgTable (var,cap) = a where
a = array ((0,0),(length var,cap)) [ ((i,j), best i j)
| i <- [0..length var] , j <- [0..cap] ] where
best 0 _ = 0
best _ 0 = 0
best i j
| snd (var !! (i-1)) > j = a!decline
| otherwise = maximum [a!decline,value+a!accept]
where decline = (i-1,j)
accept = (i-1,j - snd (var !! (i-1)))
value = fst (var !! (i-1))
--Backtracks the solution from the dynamic programming table
--Output on the form [Int] where i'th element equals 1 if
--i'th variable was accepted, 0 otherwise.
solve (var,cap) =
let j = cap
i = length var
table = dynProgTable (var,cap)
step _ 0 _ = []
step a k 0 = step table (k-1) 0 ++ [0]
step a k l
| a!(k,l) == a!(k-1,l) = step a (k-1) l ++ [0]
| otherwise = step a (k-1) (l - snd (var !! (k-1))) ++ [1]
in step table i j
In the input (var,cap), var is a list of variables in the form of 2-tuples (c,w), where c is the cost and w is the weight. cap is the maximum weight allowance.
I'm sure above code could be cleaned up to make it more readable and obvious, but that's how it turned out for me :) Where the code snippet by Landei above is short, my computer took ages computing instances with only 20 variables. The dynamic programming approach above gave me a solution for 1000 variables faster.
If you don't know about dynamic programming, you should check out this link:Lecture slides on dynamic programming, it helped me a lot.
For an introduction to arrays, check out Array tutorial.

Resources