patterns vs. guards: otherwise does not match? - haskell

The following two functions behave differently when given an empty string:
guardMatch l#(x:xs)
| x == '-' = "negative " ++ xs
| otherwise = l
patternMatch ('-':xs) = "negative " ++ xs
patternMatch l = l
Here my output:
*Main> guardMatch ""
"*** Exception: matching.hs:(1,1)-(3,20): Non-exhaustive patterns in function guardMatch
*Main> patternMatch ""
""
Question: why does not the 'otherwise' close catch the empty string?

The otherwise is within the scope of the pattern l#(x:xs), which can only match a non-empty string. It might help to see what this (effectively) translates to internally:
guardMatch l = case l of
(x :xs) -> if x == '-' then "negative " ++ xs else l
patternMatch l = case l of
('-':xs) -> "negative " ++ xs
_ -> l
(Actually, I think the if is translated to a case + guard instead of the other way around.)

A guard is always evaluated after the pattern. This is - the guard is tried iff the pattern succeeds. In your case, the pattern (x:xs) excludes the empty string, so the guards are not even tried, as the pattern fails.

The other two answers are totally right of course, but here's another way to think about it: What if you had written this?
guardMatch l#(x:xs)
| x == '-' = "negative " ++ xs
| otherwise = [x]
What would you expect guardMatch "" to be?

Related

Having trouble with isUpper function in use

Is it OK to write the otherwise part this way? The function should lower the uppercase letters and put the space in front. It keeps giving an error.
functionl s
| s==[] = error "empty"
| otherwise = [ if isUpper c then (" " ++ toLower c) else c | c <-read s::[Char] ]
First, Note that the return type of (" "++ toLower c) is a String ([Char]) if it was done properly - but it isn't. I'll show you below.
But before that, note that in this specific list comprehension, you have else c which is a single Char.
Your return types must match.
This might be a suitable replacement: concat [ if (isUpper c) then (" "++[c]) else [c] | c <-s ]
Your list comprehension is almost right as #Arnon has shown, but you could definitely implement this function more easily using recursion:
-- A descriptive name and a type signature help
-- tell other programmers what this function does
camelCaseToWords :: String -> String
camelCaseToWords [] = []
camelCaseToWords (c:cs)
| isUpper c = ' ' : toLower c : camelCaseToWords cs
| otherwise = c : camelCaseToWords cs
Now, this pattern can be abstracted to use a fold, which is Haskell's equivalent of a basic for-loop:
camelCaseToWords cs = foldr replacer [] cs
where
replacer c xs
| isUpper c = ' ' : toLower c : xs
| otherwise = c : xs
Here each step of the iteration is performed by replacer, which takes the current character c, an accumulated value xs and returns a new value to be used in the next iteration. The fold is seeded with an initial value of [], and then performed over the entire string.

Haskell - Function checks balancing within parenthesis

I have to write a function in Haskell that checks whether a string containing open and closed parenthesis is balanced. For every opened parenthesis there must be one closed and an empty string is considered balanced too.
Ex. (()) is balanced
(())) is not balanced.
()(()) is balanced.
()(())) is not balanced.
Thanks
In general keep a count. Increment if you see a ( and decrement if you see a ). If count becomes negative anywhere or is non zero at the end, you are doomed. Otherwise it is balanced.
Tested function, it works fine:
module Main where
import Data.List
balanced s = length(removePairs s) == 0
where removePairs [] = []
removePairs (x:xs)
| x == '(' = removePairs (removeLast xs 0)
| (x:xs) == ")" = "."
| x == ')' = xs
| x == '.' = (x:xs)
removeLast [] _ = "."
removeLast xs n
| ')' `notElem` xs = ")"
| (xs!!n) == ')' = (fst splitted)++(tail $ snd splitted)
| length xs == n = ")"
| otherwise = removeLast xs (n+1)
where splitted = splitAt n xs
main = print $ balanced "()()()(())" -- prints True
codepad.org

Convert Negative-base binary to Decimal in Haskell: "Instances of .. required"

I have to write two functions converting decimal numers into a (-2)adian number system (similar to binary only with -2) and vice versa.
I already have managed to get the decimal -> (-2)adian running.
But with (-2)adian -> decimal I have a problem and just don't know where to begin.
Hope you can Help me
type NegaBinary = String
-- Function (-2)adisch --> decimal
negbin_dezi :: NegaBinary -> Integer -> Integer
negbin_dezi (xs:x) n
| (x == 0) = if ([xs] == "") then 0 else (negbin_dezi [xs] (n+1))
| (x == 1) = if ([xs] == "") then (-2)**n else (-2)**n + (negbin_dezi [xs] (n+1))
It always throws:
"Instances of (Num [Char], Floating Integer) required for definition of negbin_dezi.
Anyone an idea why it wont work?
Please please please :)
You have your list pattern-matching syntax backwards. In _ : _ the first argument is the head of the list (one element), and the second is the tail of the list (another list). e.g. x:xs matched with "abc" gives x = 'a' xs = "bc". So xs:x should be x:xs. The reason for GHC asking for an instance of Num [Char], is the comparison x == 0 (and x == 1). In this, it is trying to match the type of x (String == [Char]) with the type of 0 (Num a => a), and to do this, it requires a Num instance for String.
The fix is: negbin_dezi (x:xs) n
The problem asking for an Floating Integer instance is because (**) has type Floating a => a -> a -> a, where as you want (^) which has type (Num a, Integral b) => a -> b -> a (i.e. it is restricted to integer powers.)
Once you've done this, you'll find that your algorithm doesn't work for a few reasons:
The number 0 is different to the character '0', you should be comparing x with the characters '0' and '1' rather than the numbers 0 and 1.
xs is already a string, so [xs] is a list containing a string, which isn't what you want. This is fixed by removing the square brackets.
Possibly the ordering of the reduction is wrong.
On a different note, the duplicated if statement suggests that there is some optimisations that could happen with your code. Specifically, if you handle the empty string as part of negbin_dezi then you won't have to special case it. You could write it something like
negbin_dezi "" _ = 0
negbin_dezi (x:xs) n
| n == '0' = negbin_dezi xs (n+1)
| n == '1' = (-2)^n + negbin_dezi
(This has the bonus of meaning that the function is "more total", i.e. it is defined on more inputs.)
A few more things:
The code is "stringly-typed": your data is being represented as a string, despite having more structure. A list of booleans ([Bool]) would be much better.
The algorithm can be adapted to be cleaner. For the following, I'm assuming you are storing it like "01" = -2 "001" = 4, etc. If so, then we know that number = a + (-2) * b + (-2)^2 * c ... = a + (-2) * (b + (-2) * (c + ...)) where a,b,c,... are the digits. Looking at this, we can see the stuff inside the brackets is actually the same as the whole expression, just starting at the second digit. This is easy to express in Haskell (I'm using the list-of-bools idea.):
negbin [] = 0
negbin (x:xs) = (if x then 1 else 0) + (-2) * negbin xs
And that's the whole thing. If you aren't storing it in that order, then a call to reverse fixes that! (Being really tricky, one could write
negbin = foldr (\x n -> (if x then 1 else 0) + (-2)*n) 0
)
Some problems:
x == 0 or x == 1, but x is a Char, so you mean x == '0'.
You write (xs:x). There's no pattern for matching at the end of a list. Perhaps use a helper function that reverses the list first.
[xs] has one element, and will never be "". Use a base case instead.
Pattern matching is more helpful than equality checking.
** is for floating point powers, ^ is for integer powers
You often use [xs] where you mean xs. You don't need to put square brackets to make a list.
Here's a rewrite that works:
negbin_dezi1 :: NegaBinary -> Integer
negbin_dezi1 xs = negbin (reverse xs) 0
negbin [] _ = 0
negbin (x:xs) n
| x == '0' = negbin xs (n+1)
| x == '1' = (-2)^n + (negbin xs (n+1))
It would be nicer to use pattern matching:
negbin_dezi2 :: NegaBinary -> Integer
negbin_dezi2 xs = negbin (reverse xs) 0 where
negbin [] _ = 0
negbin ('0':xs) n = negbin xs (n+1)
negbin ('1':xs) n = (-2)^n + negbin xs (n+1)
But maybe it would be nicer to convert '0' to 0 and '1' to 1 and just multiply by that:
val :: Char -> Int
val '0' = 0
val '1' = 1
negbin_dezi3 :: NegaBinary -> Integer
negbin_dezi3 xs = negbin (reverse xs) 0 where
negbin [] _ = 0
negbin (x:xs) n = val x * (-2)^n + negbin xs (n+1)
I'd not write it that way, though:
A completely different approach is to think about the whole thing at once.
"10010" -rev> [0,1,0,0,1] -means> [ 0, 1, 0, 0, 1 ]
[(-2)^0, (-2)^1, (-2)^2, (-2)^3, (-2)^4]
so let's make both lists
powers = [(-2)^n | n <- [0..]]
coefficients = reverse.map val $ xs
and multiply them
zipWith (*) powers coefficients
then add up, giving:
negbin_dezi4 xs = sum $ zipWith (*) powers coefficients
where powers = [(-2)^n | n <- [0..]]
coefficients = reverse.map val $ xs
You could rewrite powers as map ((-2)^) [0..],
or even nicer: powers = 1:map ((-2)*) powers.
(It's nicer because it reuses previous calculations and is pleasantly clean.)
this
convB2D::NegaBinary->Integer
convB2D xs|(length xs)==0 =0
|b=='0' = convB2D(drop 1 xs)
|b=='1' = val+convB2D(drop 1 xs)
|otherwise= error "invalid character "
where b=head xs
val=(-2)^((length xs)-1)
worked for me.
I on the other hand have problems to convert dec->nbin :D

Haskell - Pattern match(es) are overlapped

test :: String -> String -> Int
test' x y n = n
test' "" (y:ys) n = error "error"
test' (x:xs) "" n = error "error"
test' (x:xs) (y:ys) n =
if x == y
then test' xs ys n
else test' xs ys (n+1)
test a b = test' a b 0
When I compile this, I get this output:
Warning: Pattern match(es) are overlapped
And the answer is always "0", which is not what I intended. What is the problem with the code and how to fix it?
test' x y n = n will match for every call, the other patterns won't be considered. I think this case should be test' "" "" n = n. You get the same result if you move your original line at the end (when all other cases fail), but then you should write test' _ _ n = n which shows that you deliberately ignore some of the arguments.
[Edit]
A shorter solution would be:
test a b | length a == length b = sum $ map fromEnum $ zipWith (/=) a b
| otherwise = error "error"
The zipWith expression generates a list of Bool which is True for every difference. The function fromEnum maps False to 0 and True to 1.
The patterns are tried in order. The first of your patterns for test' always matches, so that case is always used. The first case should probably be
test' "" "" n = n
instead.

Improve a haskell script

I'm a newbie in Haskell and I'd like some opinions about improving this script. This is a code generator and requires a command line argument to generate the sql script.
./GenCode "people name:string age:integer"
Code:
import Data.List
import System.Environment (getArgs)
create_table :: String -> String
create_table str = "CREATE TABLE " ++ h (words str)
where h (x:xs) = let cab = x
final = xs
in x ++ "( " ++ create_fields xs ++ ")"
create_fields (x:xs) = takeWhile (/=':') x ++ type x ++ sig
where sig | length xs > 0 = "," ++ create_fields xs
| otherwise = " " ++ create_fields xs
create_fields [] = ""
type x | isInfixOf "string" x = " CHARACTER VARYING"
| isInfixOf "integer" x = " INTEGER"
| isInfixOf "date" x = " DATE"
| isInfixOf "serial" x = " SERIAL"
| otherwise = ""
main = mainWith
where mainWith = do
args <- getArgs
case args of
[] -> putStrLn $ "You need one argument"
(x:xs) -> putStrLn $ (create_table x)
I think you understand how to write functional code already. Here are some small style notes:
Haskell usually uses camelCase, not under_score_separation
In create_table, cabo and final are not used.
Usually a list-recursive function like create_fields puts the empty list case first.
I would not make create_fields recursive anyway. The comma-joining code is quite complicated and should be separated from the typing code. Instead do something like Data.List.intercalate "," (map create_field xs). Then create_field x can just be takeWhile (/=':') x ++ type x
Especially if there are a lot of types to be translated, you might put them into a map
Like so:
types = Data.Map.fromList [("string", "CHARACTER VARYING")
,("integer", "INTEGER")
-- etc
]
Then type can be Data.Maybe.fromMaybe "" (Data.Map.lookup x types)
Code can appear in any order, so it's nice to have main up front. (This is personal preference though)
You don't need mainWith.
Just say
main = do
args <- getArgs
case args of
[] -> ...
You don't need the dollar for the calls to putStrLn. In the first call, the argument wouldn't require parentheses anyway, and in the second, you supply the parentheses. Alternatively, you could keep the second dollar and drop the parentheses.
Don't use length xs > 0 (in sig); it needlessly counts the length of xs when all you really wanted to know is whether it's empty. Use null xs to check for a non-empty list:
...
where sig | null xs = ... -- Empty case
| otherwise = ... -- Non-empty case
or add an argument to sig and pattern match:
...
where sig (y:ys) = ...
sig [] = ...
Although Nathan Sanders' advice to replace the whole recursive thing with intercalate is excellent and makes this a moot point.
You're also identifying the type by passing the whole "var:type" string into type, so it is testing
"string" `isInfixOf` "name:string"
etc.
You could use break or span instead of takeWhile to separate the name and type earlier:
create_fields (x:xs) = xname ++ type xtype ++ sig
where
(xname, _:xtype) = break (==':') x
sig = ...
and then type can compare for string equality, or look up values using a Map.
A quick explanation of that use of break:
break (==':') "name:string" == ("name", ":string")
Then when binding
(xname, _:xtype) to ("name", ":string"),
xname -> "name"
_ -> ':' (discarded)
xtype -> "string"

Resources