Defining Tree's and Search Function - search

I am trying to define my tree and create a search function, but I think I am getting lost in the syntax of SML. Here is my tree
datatype either = ImAString of string | ImAnInt of int;
datatype eitherTree = Empty
| eLEAF of either
| eINTERIOR of (either*eitherTree*eitherTree);
This is my search function
fun eitherSearch (eLEAF(v)) x = false
| eitherSearch (eINTERIOR(ImAnInt(v), lt, rt)) x =
if x < v then eitherSearch lt v
else if x > v then eitherSearch rt v
else true;
And this is how I defined my tree
val T2 = eINTERIOR(ImAnInt(4), eLEAF(ImAnInt(1), eLEAF(ImAnInt(2), Empty, Empty), Empty), eINTERIOR(ImAnInt(3), Empty, Empty));
This returns
val T2 =
eINTERIOR
(ImAnInt 4,eINTERIOR (ImAnInt #,eINTERIOR #,Empty),
eINTERIOR (ImAnInt #,Empty,Empty)) : eitherTree
I'm guessing this isn't correct because those # symbols don't make sense. Is there a better way to define the tree so that it works in the search function? When I define a smaller tree like
val T1 = eINTERIOR(ImAnInt(5), eLEAF(ImAnInt(4)), eLEAF(ImAnInt(6)));
The search function works correctly, but in T2 I don't think I'm understanding how to write mult layered trees.

Doing if ... then ... else true is slightly redundant; often you might instead use the lazy binary operators orelse and andalso, but when you're specifically interested in whether something is less, equal or greater, use Int.compare:
if x < v then eitherSearch lt v
else if x > v then eitherSearch rt v
else true;
becomes:
case Int.compare (x, v) of
EQUAL => true
| LESS => eitherSearch lt v
| GREATER => eitherSearch rt v
You don't need three constructors in your tree; Empty, eLEAF, eINTERIOR, since you can create the same tree in different ways; this will just make functions that recurse over them more complicated. For example, the following values are equivalent:
val t1 = eINTERIOR (ImAnInt 42, Empty, Empty)
val t2 = eLEAF (ImAnInt 42)
A simpler binary tree definition could look like this:
fun eitherTree = Empty | Interior of either * eitherTree * eitherTree
You might have noticed a warning as you compile the function eitherSearch:
! Warning: pattern matching is not exhaustive
See what happens when you run it with a tree containing an ImAString ... value:
- eitherSearch (eINTERIOR (ImAString "Hello", Empty, Empty)) 42;;
! Uncaught exception:
! Match
or an Empty subtree:
- eitherSearch (eINTERIOR (ImAnInt 41, Empty, Empty)) 42;
! Uncaught exception:
! Match
Functions should ideally not crash at run-time.
Since your eitherTrees can contain both strings and ints, and your function eitherSearch explicitly looks for ints, you need to specify how it should deal with strings. It seems that you assume that eitherTrees are sorted as binary search trees as long as the nodes contain ints, but what happens when they contain strings instead? Must you then assume that the result could be in either sub-tree?
I wouldn't know how to complete the following:
fun eitherSearch Empty = false
| eitherSearch (Interior (ImAString s, lt, rt)) = ???
| eitherSearch (Interior (ImAnInt n, lt, rt)) = ...
As for T2, I can't compile it: You're using eLEAF but giving it three arguments. Perhaps in the version that you're testing with, rather than the version you posted, you are using eINTERIOR instead. This problem will go away once you (1) stick to just two constructors in your datatype definition, and (2) cover all patterns in eitherSearch.
How do I ask and answer homework questions?

Related

Is it possible to check for pointer equality in SMLNJ (for debugging)?

Suppose we have the following toy binary tree structure:
datatype Tree = Leaf | Branch of Tree * Tree
fun left(Branch(l,r))= l
fun right(Branch(l,r))= r
And suppose that we have some large and expensive to compute tree
val c: Tree= …
val d: Tree= Branch(c,c)
Can we verify in the SML/NJ interpreter that left(d) and right(d) indeed refer to the same place in memory?
(This question was borne out of working with lazy streams which may possibly contain cycles, and trying to debug whether the memoization is working correctly.)
I think we can do this by casting both values to word using Unsafe.cast, which reinterprets the pointers as numbers that can be compared with =. Here is an is function that implements this idea:
infix 4 is (* = > < >= ... *)
fun op is(a: 'a, b: 'a) = (Unsafe.cast a: word) = Unsafe.cast b
Note that:
I needed to annotate (a, b) to make sure the type checker restricts the arguments to the same type, because the typesig of is would otherwise be 'a * 'b -> bool
I needed to annotate the first Unsafe.cast application to prevent SML/NJ from having to use polyEqual and thus avoid emitting Warning: calling polyEqual
Type inference can figure out the rest just fine
Here's an example that illustrates structural sharing in vectors:
local
fun const a _ = a
val v = Vector.tabulate(1000, const #[1,2,3])
val v = Vector.update(v, 230, #[1,2,3]) (* same value, but new allocation *)
in
val test1 = Vector.sub(v, 0) is Vector.sub(v, 999)
val test2 = Vector.sub(v, 0) is Vector.sub(v, 230)
end
And it does work as expected. The repl answers with
(* val test1 = true : bool
val test2 = false : bool *)
Now here's the tree example from your question:
local
datatype Tree
= Leaf
| Branch of Tree * Tree
fun left (Branch(l,r)) = l
fun right (Branch(l,r)) = r
val c = Branch(Leaf,Leaf) (* imagine it being something complex *)
val d = Branch(c, c)
in
val test3 = left d is right d
end
When we try it, it answers correctly:
(* val test3 = true : bool *)
I think this answers your question. Below this point I talk about the choice of word and a little about what might be happening internally when we convert to it
As far as I'm aware, SML/NJ does pointer tagging like many lisps, v8, OCaml, etc.. which means we want to cast specifically to a type which isn't heap-allocated.. because we want to be able to read the pointer value, not misinterpret heap objects.
I think word works fine for that purpose; it's immediate like an int, and unsigned unlike it.. so it should correspond to the memory address (don't hold me up on that).
There seems to be a bug* that prevents you from inspecting the word value directly in the repl, it may be the pointer tagging at play.
* at least the compiler reports it as that? as of v110.99
One workaround is to immediately convert the value to a different representation (perhaps being boxed is required?), like a string, or Word64.word
fun addrOf x = Word.toString (Unsafe.cast x)
Indeed, when we try to use our newly defined addrOf function to compare the address versus its stringified value we can observe the effects of pointer tagging
(* We'll need these definitions onwards, might as well have them here: *)
infix 5 >> <<
val op >> = Word.>>
val op << = Word.<<
val unsafeWord = Option.valOf o Word.fromString
local
val x = SOME 31 (* dummy boxed value *)
val addr = unsafeWord (addrOf x)
in
val test4 = Unsafe.cast x = addr
val test5 = Unsafe.cast x >> 0w1 = addr >> 0w1 (* get rid of lowest bit *)
end
(* val test4 = false : bool
val test5 = true : bool *)
So then, if it's the case that the tag is just the lowest bit of a machine word in SML/NJ, like it is in many tagged pointer implementations, then the pointer should be, accurately, the casting value shifted right once, then left once again.
fun addrOf x = Unsafe.cast x >> 0w1 << 0w1
The reason we do this seemingly nop conversion (remember, all pointers are even) is because it properly tags the cast word value in the process.
If we shift left first then right, the tag itself would find its way to the value with the first operation as the coerced pointer turns into proper word.. that's why we shift right first instead.. Shifting left from that zero-fills the lower bit, so no info about the address is lost, but an immediate value tag is properly present internally.
local
fun strAddrOf x = Word.toString (Unsafe.cast x)
fun isEven x = Word.andb (x, 0w1) = 0w0
val x = SOME 42
val ogAddr = unsafeWord (strAddrOf x) (* a known-correct conversion: no shifting takes place *)
val badAddr = Unsafe.cast x << 0w1 >> 0w1
val goodAddr = Unsafe.cast x >> 0w1 << 0w1
in
val test6 = ogAddr = badAddr
val test7 = ogAddr = goodAddr
val test8 = isEven ogAddr
end
(* val test6 = false : bool
val test7 = true : bool
val test8 = true : bool *)
This shifting in addrOf allows you to get the pointer value directly without intermediate conversions (and boxing) to string or word64. Of course, this solution breaks down with actual unboxed values so it's good to test for whether the object is boxed to begin with (Unsafe.boxed) in your addrOf definition, and return 0wx0 in case you were working with immediates.
Hope this works for your purposes. It certainly did for mine so far!

Finding if a string is a substring of another in Sml without library functions

I am trying to write a function that subString : string * string -> int
that checks if the first string is a substring of the second and its case sensitive.
I want to return the index starting from 0 if the first string is a substring or -1 if it is not. if it appears multiple times just return the index of the first appearance.
for instance:
subString("bc","abcabc") ===>1
subString("aaa","aaaa") ===>0
subString("bc","ABC") ===>-1
I am having a lot of trouble wrapping my brain around this because I am not too familiar with sml or using strings in sml and I am not supposed to use any built in functions like String.sub.
I can use helper functions though.
all I can think of is to use explode somehow in a helper function and somehow check the lists and then implode them, but how do I get the indexed position?
all I have is
fun subString(s1,s2) =
if null s2 then ~1
else if s1 = s2 then 0
else 1+subString(s1, tl s2);
I am thinking of using a helper function that explodes the strings and then maybe compares the two but I can't figure how to get that to work.
This is already a really good start, but there are some slight problems:
In your recursive case you add 1 to the recursive result, even if the recursive application did not find the substring and returned -1. You should check wether the result is -1 before adding 1.
In the second line you check whether the two strings are equal. If you do this you will only find a substring if the string ends with that substring. So what you really want to do in line 2 is to test whether s2 starts with s1. I would recommend that you write a helper function that performs that test. For this helper function you could indeed use explode and then recursively check whether the first character of the lists are identical.
Once you have this helper function use it in line 2 instead of the equality test.
I am not supposed to use any built in functions like String.sub
What a pity! Since strings have an abstract interface while you with lists have direct access to its primary constructors, [] and ::, you have to use library functions to get anywhere with strings. explode is also a library function. But okay, if your constraint is that you have to convert your string into a list to solve the exercise, so be it.
Given your current code,
fun subString(s1,s2) =
if null s2 then ~1
else if s1 = s2 then 0
else 1+subString(s1, tl s2);
I sense one problem here:
subString ([#"b",#"c"], [#"a",#"b",#"c",#"d"])
~> if null ([#"a",#"b",#"c",#"d"]) then ... else
if [#"b",#"c"] = [#"a",#"b",#"c",#"d"] then ... else
1 + subString([#"b",#"c"], [#"b",#"c",#"d"])
~> 1 + subString([#"b",#"c"], [#"b",#"c",#"d"])
~> 1 + if null ([#"b",#"c",#"d"]) then ... else
if [#"b",#"c"] = [#"b",#"c",#"d"] then ... else
1 + subString([#"b",#"c"], [#"c",#"d"])
It seems that the check s1 = s2 is not exactly enough: We should have liked to say that [#"b",#"c"] is a substring of [#"b",#"c",#"d"] because it's a prefix of it, not because it is equivalent. With s1 = s2 you end up checking that something is a valid suffix, not a valid substring. So you need to change s1 = s2 into something smarter.
Perhaps you can build a helper function that determines if one list is a prefix of another and use that here?
As for solving this exercise by explodeing your strings into lists: This is highly inefficient, so much that Standard ML's sister language Ocaml had explode entirely removed from the library:
The functions explode and implode were in older versions of Caml, but we omitted them from OCaml because they encourage inefficient code. It is generally a bad idea to treat a string as a list of characters, and seeing it as an array of characters is a much better fit to the actual implementation.
So first off, String.isSubstring already exists, so this is a solved problem. But if it weren't, and one wanted to write this compositionally, and String.sub isn't cheating (it is accessing a character in a string, comparable to pattern matching the head and tail of a list via x::xs), then let me encourage you to write efficient, composable and functional code:
(* Check that a predicate holds for all (c, i) of s, where
* s is a string, c is every character in that string, and
* i is the position of c in s. *)
fun alli s p =
let val stop = String.size s
fun go i = i = stop orelse p (String.sub (s, i), i) andalso go (i + 1)
in go 0 end
(* needle is a prefix of haystack from the start'th index *)
fun isPrefixFrom (needle, haystack, start) =
String.size needle + start <= String.size haystack andalso
alli needle (fn (c, i) => String.sub (haystack, i + start) = c)
(* needle is a prefix of haystack if it is from the 0th index *)
fun isPrefix (needle, haystack) =
isPrefixFrom (needle, haystack, 0)
(* needle is a substring of haystack if is a prefix from any index *)
fun isSubstring (needle, haystack) =
let fun go i =
String.size needle + i <= String.size haystack andalso
(isPrefixFrom (needle, haystack, i) orelse go (i + 1))
in go 0 end
The general idea here, which you can re-use when building an isSubstring that uses list recursion rather than string index recursion, is to build the algorithm abstractly: needle being a substring of haystack can be defined in simpler terms by needle being the prefix of haystack counting from any valid position in haystack (of course not such that it exceeds haystack). And determining if something is a prefix is much easier, even easier with list recursion!
This suggestion would leave you with a template,
fun isPrefix ([], _) = ...
| isPrefix (_, []) = ...
| isPrefix (x::xs, y::ys) = ...
fun isSubstring ([], _) = ...
| isSubstring (xs, ys) = ... isPrefix ... orelse ...
As for optimizing the string index recursive solution, you could avoid the double bounds checking in both isPrefixFrom and in isSubstring by making isPrefixFrom a local function only accessible to isPrefix and isSubstring; otherwise it will be unsafe.
Testing this,
- isSubstring ("bc", "bc");
> val it = true : bool
- isSubstring ("bc", "bcd");
> val it = true : bool
- isSubstring ("bc", "abc");
> val it = true : bool
- isSubstring ("bc", "abcd");
> val it = true : bool
- isSubstring ("bc", "");
> val it = false : bool

haskell: factors of a natural number

I'm trying to write a function in Haskell that calculates all factors of a given number except itself.
The result should look something like this:
factorlist 15 => [1,3,5]
I'm new to Haskell and the whole recursion subject, which I'm pretty sure I'm suppoused to apply in this example but I don't know where or how.
My idea was to compare the given number with the first element of a list from 1 to n div2
with the mod function but somehow recursively and if the result is 0 then I add the number on a new list. (I hope this make sense)
I would appreciate any help on this matter
Here is my code until now: (it doesn't work.. but somehow to illustrate my idea)
factorList :: Int -> [Int]
factorList n |n `mod` head [1..n`div`2] == 0 = x:[]
There are several ways to handle this. But first of all, lets write a small little helper:
isFactorOf :: Integral a => a -> a -> Bool
isFactorOf x n = n `mod` x == 0
That way we can write 12 `isFactorOf` 24 and get either True or False. For the recursive part, lets assume that we use a function with two arguments: one being the number we want to factorize, the second the factor, which we're currently testing. We're only testing factors lesser or equal to n `div` 2, and this leads to:
createList n f | f <= n `div` 2 = if f `isFactorOf` n
then f : next
else next
| otherwise = []
where next = createList n (f + 1)
So if the second parameter is a factor of n, we add it onto the list and proceed, otherwise we just proceed. We do this only as long as f <= n `div` 2. Now in order to create factorList, we can simply use createList with a sufficient second parameter:
factorList n = createList n 1
The recursion is hidden in createList. As such, createList is a worker, and you could hide it in a where inside of factorList.
Note that one could easily define factorList with filter or list comprehensions:
factorList' n = filter (`isFactorOf` n) [1 .. n `div` 2]
factorList'' n = [ x | x <- [1 .. n`div` 2], x `isFactorOf` n]
But in this case you wouldn't have written the recursion yourself.
Further exercises:
Try to implement the filter function yourself.
Create another function, which returns only prime factors. You can either use your previous result and write a prime filter, or write a recursive function which generates them directly (latter is faster).
#Zeta's answer is interesting. But if you're new to Haskell like I am, you may want a "simple" answer to start with. (Just to get the basic recursion pattern...and to understand the indenting, and things like that.)
I'm not going to divide anything by 2 and I will include the number itself. So factorlist 15 => [1,3,5,15] in my example:
factorList :: Int -> [Int]
factorList value = factorsGreaterOrEqual 1
where
factorsGreaterOrEqual test
| (test == value) = [value]
| (value `mod` test == 0) = test : restOfFactors
| otherwise = restOfFactors
where restOfFactors = factorsGreaterOrEqual (test + 1)
The first line is the type signature, which you already knew about. The type signature doesn't have to live right next to the list of pattern definitions for a function, (though the patterns themselves need to be all together on sequential lines).
Then factorList is defined in terms of a helper function. This helper function is defined in a where clause...that means it is local and has access to the value parameter. Were we to define factorsGreaterOrEqual globally, then it would need two parameters as value would not be in scope, e.g.
factorsGreaterOrEqual 4 15 => [5,15]
You might argue that factorsGreaterOrEqual is a useful function in its own right. Maybe it is, maybe it isn't. But in this case we're going to say it isn't of general use besides to help us define factorList...so using the where clause and picking up value implicitly is cleaner.
The indentation rules of Haskell are (to my tastes) weird, but here they are summarized. I'm indenting with two spaces here because it grows too far right if you use 4.
Having a list of boolean tests with that pipe character in front are called "guards" in Haskell. I simply establish the terminal condition as being when the test hits the value; so factorsGreaterOrEqual N = [N] if we were doing a call to factorList N. Then we decide whether to concatenate the test number into the list by whether dividing the value by it has no remainder. (otherwise is a Haskell keyword, kind of like default in C-like switch statements for the fall-through case)
Showing another level of nesting and another implicit parameter demonstration, I added a where clause to locally define a function called restOfFactors. There is no need to pass test as a parameter to restOfFactors because it lives "in the scope" of factorsGreaterOrEqual...and as that lives in the scope of factorList then value is available as well.

Translate list comprehension to Prolog

I have a list comprehension in Haskell that I want to translate to Prolog.
The point of the list comprehension is rotating a 4 by 4 grid:
rotate :: [Int] -> [Int]
rotate grid = [ grid !! (a + 4 * b) | a <- [0..3], b <- [0..3] ]
Now in Prolog, I translated it like this:
rotateGrid([T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15],
[T0,T4,T8,T12,T1,T5,T9,T13,T2,T6,T10,T14,T3,T7,T11,T15]).
Can we do better?
We can use findall/3 for list comprehensions (Cf. the SWI-Prolog Documentation). E.g.,
?- findall(X, between(1,10,X), Xs).
Xs = [1,2,3,4,5,6,7,8,9,10]
Xs is a list holding all values that can unify with X when X is a number between 1 and 10. This is roughly equivalent to the Haskell expression let Xs = [x | x <- [1..10]](1). You can read a findall/3 statement thus: "find all values of [First Argument] such that [Conditions in Second Argument] hold, and put those values in the list, [Third Argument]".
I've used findall/3 to write a predicate rotate_grid(+Grid, ?RotatedGrid). Here is a list of the approximate Haskell-Prolog equivalences I used in the predicate; each line shows the relation between the value that the Haskell expression will evaluate to and the Prolog variable with the same value:
a <- [0..3] = A in between(0, 3, A)
b <- [0..3] = B in between(0, 3, B)
(a + 4 * d) = X in X is A + 4 * D
<Grid> !! <Index> = Element in nth0(Index, Grid, Element)
Then we simply need to find all the values of Element:
rotate_grid(Grid, RotatedGrid) :-
findall( Element,
( between(0,3,A),
between(0,3,B),
Index is A + 4 * B,
nth0(Index, Grid, Element) ),
RotatedGrid
).
To verify that this produces the right transformation, I down-cased the Prolog code from the question and posed the following query:
?- rotate_grid([t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15],
[t0,t4,t8,t12,t1,t5,t9,t13,t2,t6,t10,t14,t3,t7,t11,t15]).
| true.
Footnotes:
(1): between/3 isn't actually the analogue of [m..n], since the latter returns a list of values from m to n where between(M,N,X) will instantiate X with each value between M and N (inclusive) on backtracking. To get a list of numbers in SWI-Prolog, we can use numlist(M,N,Ns). So a stricter analogue for x <- [1.10] would be the conjunction member(X, Ns), numlist(1, 10, Ns).
You want a permutation of a list. The concrete elements are not considered. Therefore, you can generalize your Haskell signature to
rotate :: [x] -> [x]
This is already a very valuable hint for Prolog: the list's elements will not be considered - elements will not even be compared. So a Prolog solution should be able to handle variables directly, like so:
?- rotateGrid(L,R).
L = [_A,_B,_C,_D,_E,_F,_G,_H,_I,_J,_K,_L,_M,_N,_O,_P],
R = [_A,_E,_I,_M,_B,_F,_J,_N,_C,_G,_K,_O,_D,_H,_L,_P].
And your original definition handles this perfectly.
Your version using list comprehensions suggests itself to be realized via backtracking, certain precautions have to be taken. Using findall/3, as suggested by #aBathologist will rename variables:
?- length(L,16),rotate_grid(L,R).
L = [_A,_B,_C,_D,_E,_F,_G,_H,_I,_J,_K,_L,_M,_N,_O,_P],
R = [_Q,_R,_S,_T,_U,_V,_W,_X,_Y,_Z,_A1,_B1,_C1,_D1,_E1,_F1].
The built-in predicate bagof/3 addresses this problem. Note that we have to declare all local, existential variables explicitly:
rotate_grid2(Grid, RotatedGrid) :-
bagof(
Element,
A^B^Index^ % declaration of existential variables
( between(0,3,A),
between(0,3,B),
Index is A + 4 * B,
nth0(Index, Grid, Element)
),
RotatedGrid).
For lists that are shorter than 16 elements, the Haskell version produces a clean error, but here we get pretty random results:
?- L=[1,2,3,4],rotate_grid(L,R).
L = [1,2,3,4], R = [1,2,3,4].
?- L=[1,2,3,4,5],rotate_grid(L,R).
L = [1,2,3,4,5], R = [1,5,2,3,4].
This is due to the unclear separation between the part that enumerates and "generates" a concrete element. The cleanest way is to add length(Grid, 16) prior to the goal bagof/3.
List comprehensions in Prolog
Currently, only B-Prolog offers a form of list comprehensions:
R#=[E: A in 0..3,B in 0..3,[E,I],(I is A+4*B,nth0(I,L,E))].
However, it does not address the second problem:
| ?- L = [1,2,3], R#=[E: A in 0..3,B in 0..3,[E,I],(I is A+4*B,nth0(I,L,E))].
L = [1,2,3]
R = [1,2,3]
yes
Use a loop predicate foreach/4
If the comprehension should retain variables, which is for example important in constraint programming, a Prolog system could offer a predicate foreach/4. This predicate is the DCG buddy of foreach/2.
Here is how variables are not retained via findall/3, the
result R contains fresh variables according to the ISO
core semantics of findall/3:
Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.1)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
?- functor(L,foo,5), findall(X,
(between(1,5,N), M is 6-N, arg(M,L,X)), R).
L = foo(_5140, _5142, _5144, _5146, _5148),
R = [_5210, _5204, _5198, _5192, _5186].
And here is how variables can be retained via foreach/4,
the resulting list has the same variables as the compound
we started with:
Jekejeke Prolog 3, Runtime Library 1.3.0
(c) 1985-2018, XLOG Technologies GmbH, Switzerland
?- [user].
helper(N,L) --> [X], {M is 6-N, arg(M,L,X)}.
Yes
?- functor(L,foo,5), foreach(between(1,5,N),helper(N,L),R,[]).
L = foo(_A,_G,_M,_S,_Y),
R = [_Y,_S,_M,_G,_A]
Using foreach/4 instead of bagof/3 might seem a little bit over the top. foreach/4 will probably only show its full potential when implementing Picat loops, since it can build up constraints, what bagof/3 cannot do.
foreach/4 is an implementation without the full materialization of all solution that are then backtracked. It shares with bagof/3 the reconstruct of variables, but still allows backtracking in the conjunction of the closures.

Graph function in Haskell

I have such a data type :
data Node a = Node
{ label :: a,
adjacent :: [(a,Int)] } deriving Show
Example : ( Node 'a' [ ( 'b' , 3 ) , ( 'c' ,2 ) ] )
I want to get the label from this structure, I wrote this function (and several other combinations which I thought might work) :
giveLabel Node a [(c,b)] = a;
But I keep getting errors. Can you tell me how should I change my function? Thanks
giveLabel (Node a [(c,b)]) = a
Is the syntax you want - defining functions uses the same rules of precedence as calling them, and according to those rules, you defined a function giveLabel with three arguments (Node, a, and [c,b]); and that was illegal because in that context Node was missing arguments.
Even that probably isn't what you want - the pattern [(c,b)] only matches lists with exactly one item in. Since you don't care about the list of neighbours you can write:
giveLabel (Node a xs) = a
...where xs will bind to the whole list of neighbours; but actually since you don't even care about that, you can write:
giveLabel (Node a _) = a
...where _ is a useful way of pattern matching against a parameter you aren't going to use.

Resources