I recently started learning Haskell and I'm trying to rewrite something I did for an interview in python in Haskell. I'm trying to convert a string from camel case to underscore separated ("myVariableName" -> "my_variable_name"), and also throw an error if the first character is upper case.
Here's what I have:
import qualified Data.Char as Char
translate_java :: String -> String
translate_java xs = translate_helper $ enumerate xs
where
translate_helper [] = []
translate_helper ((a, num):xs)
| num == 1 and Char.isUpper a = error "cannot start with upper"
| Char.isUpper a = '_' : Char.toLower a : translate_helper xs
| otherwise = a : translate_helper xs
enumerate :: (Num b, Enum b) => [a] -> [(a,b)]
enumerate xs = zip xs [1..]
I realize It's pretty likely I'm going about this in a weird way, and I'd love advice about better ways to implement this, but I'd like to get this to compile as well. Here's the error I'm getting now:
Prelude> :r
[1 of 1] Compiling Main ( translate.hs, interpreted )
translate.hs:4:20:
No instance for (Num
(([Bool] -> Bool) -> (Char -> Bool) -> Char -> t))
arising from a use of `translate_helper' at translate.hs:4:20-35
Possible fix:
add an instance declaration for
(Num (([Bool] -> Bool) -> (Char -> Bool) -> Char -> t))
In the first argument of `($)', namely `translate_helper'
In the expression: translate_helper $ enumerate xs
In the definition of `translate_java':
translate_java xs
= translate_helper $ enumerate xs
where
translate_helper [] = []
translate_helper ((a, num) : xs)
| num == 1 and Char.isUpper a
= error "cannot start with upper
"
| Char.isUpper a
= '_' : Char.toLower a : transla
te_helper xs
| otherwise = a : translate_help
er xs
Failed, modules loaded: none.
Any explanation of what's going on here would be great. I really don't understand where "(Num (([Bool] -> Bool) -> (Char -> Bool) -> Char -> t))" is coming from. I'd think the type declaration for translate_helper would be something like [(a,b)] -> [a]?
You have to replace and by &&. The first one is a function (prefix) that receives a list of boolean values and calculates an and of them all. The second one is a true logical and. The error message is a little bit confusing though. Whenever I get such a strange error message, I usually start to annotate my code with type signatures. Then the compiler is able to give you a more detailed description of what went wrong.
Others have mentioned that you should use (&&) instead of and, so I'll answer your other question: no, I don't think you're going about this in a weird way.
But... I do think it can be even more elegant!
translate_java (x:xs) | isUpper x = error "cannot start with an upper"
translate_java xs = concatMap translate xs where
translate x = ['_' | isUpper x] ++ [toLower x]
There's a few interesting things going on here:
The special case is checked straight away. Don't wait until you're recursing to do this!
The concatMap function is really handy in a lot of cases. It's just a map followed by a concat. If I were writing this myself, I'd probably use xs >>= translate instead.
That ['_' | isUpper x] is a list comprehension; this is a cute idiom for making a list with either 0 or 1 elements in it, depending on whether a predicate holds.
Other than that, the code should be fairly self-explanatory.
The problem is this:
| num == 1 and Char.isUpper a = ...
and is not an infix operator; rather it is a function:
and :: [Bool] -> Bool
So it is interpreting 1 and Char.isUpper a as applying three arguments to the "function" 1. Use && instead.
The error message comes from the way numerals are interpreted. A numeral, say, 1 is actually polymorphic; the specific type it gets depends on the type that is needed. That's why you can say x+1 and it will work whether x is an integer or a double or whatever. So the compiler inferred that the type of 1 needs to be a three-argument function, and then tried to find a numeric type matching that so it could convert 1 into that type (and, naturally, failed).
Here's my solution. It's not as masterful as the answer Daniel Wagner gave using concatMap and the list comprehension, but it's perhaps easier to understand for the beginner.
conv :: String -> String
conv [] = []
conv s#(x:xs) = if Char.isUpper x
then error "First character cannot be uppercase"
else change s
change :: String -> String
change [] = []
change (x:xs) = if Char.isUpper x
then '_' : Char.toLower x : change xs
else x : change xs
The function conv really just checks your criterion that the first character must not be uppercase, and if it isn't it hands over the string to the function change, which does the work. It goes through all the characters one by one, building a list, and if the character is uppercase, it adds an underscore followed by the lowercase version of the character, otherwise if the character is already lowercase it just adds it as it is.
Related
I'm trying to figure out what is the best practice to write the Haskell equivalent of assert(0). I know that type safety dictates that an integer must be returned from scanList, however I wonder if there's a better way than what I wrote. Is there any way to avoid the arbitrary number 923 that is just stuck there?
module Main (main) where
import Control.Exception (assert)
l = [
Left "1",
Left "1",
Right 1,
Right 1,
Left "9"]
scanList :: [ Either String Int ] -> Int
scanList [ ] = 0
scanList (x:xs) = case x of
Right i -> i + scanList xs
Left s ->
if read s < 8
then read s + scanList xs
else assert False $ 923
main = do
print $ scanList l
From the documentation of assert:
If the first argument evaluates to True, then the result is the second argument. Otherwise an AssertionFailed exception is raised, containing a String with the source file and line number of the call to assert.
So instead of giving False as first argument you could actually check your if condition there:
scanList (x:xs) = case x of
Right i -> i + scanList xs
Left s ->
assert (read s < 8) (read s + scanList xs)
The more idiomatic Haskell design would be to keep pure functions total. When using assert, you're throwing an exception, which makes the function partial. This means that you can no longer trust the type of the function. It claims to have the type [Either String Int] -> Int, but will fail with an exception at run-time under various conditions.
A total function would either stay within the Either monad, or could, alternatively, translate to Maybe:
import Text.Read
scanList :: (Num a, Read a, Ord a) => [Either String a] -> Maybe a
scanList [] = Just 0
scanList (x:xs) =
case x of
Right i -> fmap (+ i) $ scanList xs
Left s ->
case readMaybe s of
Just i -> if i < 8 then fmap (+ i) $ scanList xs else Nothing
Nothing -> Nothing
You could simplify the code quite a bit, but I chose to keep it structurally as close to the OP as possible.
With a type like [Either String a] -> Maybe a, any caller knows that they have to handle both Just and Nothing cases, without having to resort to reading the code or documentation of the function in question.
I try to write a program for an exercise. It should read a String and return an empty list if it could parse the String according to a given grammar. In case the String is not in valid grammar it should return "Nothing". Like here:
>prog "c+c*c$"
Just""
>prog "c+c-c$"
Nothing
I wrote the following functions they are loaded and compile in GHCI, but when i run prog with any argument i get the following exception: *** Exception: Maybe.fromJust: Nothing
I suppose i access or pass a Maybe String in a wrong way, but not sure where. Any help regarding the right handling of Maybe structures are welcome.
Here is my code:
import Data.Maybe
match :: Char -> Maybe String -> Maybe String
match x input
| (isNothing input == False) && (x == head (fromJust(input))) = Just (tail (fromJust(input)))
| otherwise = Nothing
prog :: String -> Maybe String
prog x = match '$' (expr (Just (x)))
expr :: Maybe String -> Maybe String
expr x = ttail (term x)
term :: Maybe String -> Maybe String
term x = ftail (factor x)
ttail :: Maybe String -> Maybe String
ttail x
| fromJust(x) == [] = Just []
| otherwise = ttail (term (match '+' x))
factor :: Maybe String -> Maybe String
factor x = match 'c' x
ftail :: Maybe String -> Maybe String
ftail x
| fromJust(x) == [] = Just []
| otherwise = ftail ( factor ( match '*' x))
There are several antipatterns in the OP's code. I'll only discuss this snippet.
match :: Char -> Maybe String -> Maybe String
match x input
| (isNothing input == False) && (x == head (fromJust(input))) = Just (tail (fromJust(input)))
| otherwise = Nothing
Using isNothing, fromJust is an antipattern, since the latter is a partial function which crashes the program when fed with Nothing. The programmer has to be careful to always check isJust beforehand, which is easy to forget. It is much simpler to forget about these functions completely and rely on pattern matching instead (see below).
.. == False should be rewritten as not ..
not (isNothing ..) should be isJust .. (but again, pattern matching makes this pointless)
head,tail,!! are partial functions too, and they should be replaced with pattern matching, when possible. Above, head is potentially called on [], so we would need to check it beforehand. Pattern matching avoids the need.
Instead of .. == [] one can use null .. (or, better, pattern matching).
Never write f(x) for a function call, the parentheses have no purpose there.
Turn on warnings using the -Wall flag: the compiler often spots issues in the code.
If you are learning Haskell, I strongly suggest you refrain from using dangerous partial functions and read a tutorial on pattern patching, using which would prevent almost all the issues in your code.
For comparison, the code above could be rewritten as:
match :: Char -> Maybe String -> Maybe String
match x (Just (y:ys)) | x==y = Just ys
match _ _ = Nothing
Note how pattern matching simultaneously checks whether the argument is a Just with a non empty list inside, and extracts the data inside the constructors. When it fails, the next case of the match is taken (instead of crashing the program).
In languages without pattern matching (say, Java), often libraries force us to remember to check whether data is present (x.hasNext()) before accessing the data (x.next()). Forgetting the check causes a runtime error / exception. With pattern matching, these two steps are combined in the same language construct, so that there is no way to "forget" a check and crash the program.
Unlike the original code, match x (Just []) does not crash but returns Nothing instead.
fromJust expects to be passed a Just value and it receives a Nothingvalue, this is why this exception happens:
http://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Maybe.html#v:fromJust
Note that I would encourage you to use the maybe function which could help clarify your code I think ( and ... maybe find the bug :) )
Also, maybe is preferable over fromJust because it's not a partial function (i.e it is guaranteed that the function won't error at runtime)
for example it allows you to rewrite :
match :: Char -> Maybe String -> Maybe String
match x input
| (isNothing input == False) && (x == head (fromJust(input))) = Just (tail (fromJust(input)))
| otherwise = Nothing
as
match :: Char -> Maybe String -> Maybe String
match x input =
maybe
Nothing
(\i ->
if x == head i
then Just $ tail i
else Nothing)
input
One more thing : head and tailĀ are partial functions too, you'd prefer using pattern matching like this, to avoid runtime exceptions when the String is empty for example:
match :: Char -> Maybe String -> Maybe String
match x input =
maybe
Nothing
(\i -> case i of
[] -> Nothing
first:rest ->
if x == first
then Just rest
else Nothing)
input
(Edit: also, see the answer of #chi that gives a nice idiomatic implementation of match!)
I'm sure these are both very stupid mistakes, but i'm trying to convert and print two lists , and i'm getting an error on ghci.
First, i want to convert from this:
["2","2","2"]
to this
[2,2,2]
for that, i wrote this function:
convert (x:xs) = [read x | x <- xs]
but that doesn't seem to be working...
Second:
Here's my printing function:
print_results [] _ = error("Empty List!")
print_results _ [] = error("Empty List!")
print_results (x:xs) (y:ys) = print x ++ " + " ++ print y : print_results xs ys
For this input:
[2,2,2] and [3,3,3]
The desired output should be:
2 + 3
2 + 3
2 + 3
Thanks in advance!
These are not "stupid" mistakes, but you're going to have to step back a bit from "what type do I write here" in order to make sense of what's going on. I notice you've asked a bunch of overlapping questions today surrounding these issues. I hope we as a community can get you an answer that will get you on the right track. In that light, I'm marking this post Community Wiki and encouraging others to edit it.
In Haskell, every value has a specific, concrete type. We can write functions that work on multiple types. Some of them work on all types: replicate 5 :: a -> [a] doesn't care at all about what a is. Some work only on some types: read :: Read a => String -> a requires that a be an instance of the class Read.
For now, you should assume that, in order to actually run a function and print a result in GHCi or compiled code, you need to replace all type variables to specific types. (This is wrong in lots of ways that I or others will probably expand on.)
After writing a function, ask GHCi for its inferred type, which is usually the most general signature possible:
> :t map read
map read :: Read a -> [String] -> [a]
> :t map read $ ["as","ew"]
> map read $ ["as","ew"] :: Read a => [a]
Notice that we still have a type variable in there. We need to choose a specific type. What #chi and I both encouraged you to do was to add a type annotation somewhere to fix that type. But if you fix that type to Int, you're trying to parse "as" and "ew" as numbers, which obviously fails.
First:
convert :: [String] -> [Int]
convert xs = [read x | x <- xs]
or even
convert :: [String] -> [Int]
convert = map read
Note that the type annotation matters, since without it Haskell does not how how it should read the string (as an Int? a Char? a tree? a list? etc.)
Second:
print_results [] [] = []
print_results [] _ = error "Empty List!"
print_results _ [] = error "Empty List!"
print_results (x:xs) (y:ys) = (show x ++ " + " ++ show y) : print_results xs ys
The above will compute a list of strings, formatted as you wanted. If you really want to print them doing an IO action, you can use
mapM_ putStrLn (print_results list1 list2)
I'm trying to solve the 8 queens problem in Haskell without the use of any advanced functions, only with basic knowledge. I have come this far only but I'm getting an error that I can't understand.
The code:
queens = [[x1,x2,x3,x4,x5,x6,x7,x8] | x1<-[1..8], x2<-[1..8],
x3<-[1..8], x4<-[1..8], x5<-[1..8],
x6<-[1..8], x7<-[1..8], x8<-[1..8],
safeH [x2,x3,x4,x5,x6,x7,x8] x1]
safeH xs e = if length xs == 1 then head xs
else e /= safeH (tail xs) (head xs)
and the error message is:
y.hs:1:42:
No instance for (Num Bool) arising from the literal `1'
Possible fix: add an instance declaration for (Num Bool)
In the expression: 1
In the expression: [1 .. 8]
In a stmt of a list comprehension: x1 <- [1 .. 8]
[1 of 1] Compiling Main ( y.hs, interpreted )
Failed, modules loaded: none.
The culprit is
.........
safeH [x2,x3,x4,x5,x6,x7,x8] x1]
safeH xs e = if length xs == 1 then head xs
else e /= safeH (tail xs) (head xs)
specifically,
else e /= safeH (tail xs) (head xs)
because e == x1. So on the one hand safeH returns Bool, being used as a test in the list comprehension. OTOH you compare its result with x1. Which is 1, among other things (x1<-[1..8]). I.e. Num1. Which must also be a Bool. Hence the error.
1 A numeric literal such as 1 is parsed as a value of a polymorphic type Num a => a. I.e. its concrete type must belong to the Num type class. Since the concrete type is also determined to be Bool here, this means that Bool must belong to the Num type class, for this code to typecheck. Hence the instance for (Num Bool) is sought.
The if ... then ... else ... expression in safeH is not well-typed:
safeH l e = if length l == 1 then head l
else e /= safeH(tail l)(head l)
The then branch is incorrectly returning a numeric type, while the else branch is returning a boolean type Bool, as I think you intended.
You should add type signatures to all your top-level functions as a way of documenting what your code does, organizing your thoughts, and making errors easy to understand; the error message here is needlessly confusing because GHC infers that your code is returning some Num type thing from the first branch, and so when the second branch returns Bool GHC complains about the wrong thing: there being no instance of Num for the Bool type).
You should also read about pattern matching on lists, and take a look at the implementation of length and think about why it's not the best way to implement your function here.
So instead of using length and head, start with this framework:
safeH :: [Int] -> Int -> Bool
safeH [n] e = -- the case for a 1-length list
safeH (n:ns) e = -- ???
When you get something working then try redefining it where the base case is the empty list [].
So I have the following function:
chk2 :: [(Integer,Integer)] -> Either [(Integer,Integer)] (Integer,Integer)
chk2 i#((n,_):_)
| chkp (prod $ lgst i)==True = Right $ lgst i
| lgst i==i!!0 = Left $ chk2 $ (4-2,4-2):next i
| otherwise = Left $ chk2 $ next i
where prod (a,b) = a*b
lgst = foldl1 (\(a,b) (c,d) -> if prod (a,b) > prod (c,d) then (a,b) else (c,d))
next t = map (\(a,b) -> if (a,b)==lgst t then (a-1,b+1) else (a,b)) t
along with this error:
runhugs: Error occurred
ERROR "4/4.hs":14 - Type error in explicitly typed binding
*** Term : chk2
*** Type : [(Integer,Integer)] -> Either (Either [(Integer,Integer (Integer,Integer)) (Integer,Integer)
*** Does not match : [(Integer,Integer)] -> Either [(Integer,Integer)] (Integer,Integer)
I'm trying to get this function to either end up with an (a,b) i.e. first guard or [(a,b)] i.e. the latter two guards. The basic problem is in the latter two guards.. if I take out the recursion, everything works fine, but I'm not sure how to define the type signature when returning the function itself.
The problem is with how you recurse.
According to the type of chk2, chk2 $ next i is of type Either [(Integer,Integer)] (Integer,Integer). Left is of type b -> Either b a, so Left $ chk2 $ next i is of type Either (Either [(Integer,Integer)] (Integer,Integer)) a for some unspecified type a.
Left $ chk2 $ (4-2,4-2):next i has a similar problem.
To fix, you need to decide how you want to handle the recursive value.
Easy fix:
| lgst i==i!!0 = chk2 $ (4-2,4-2):next i
| otherwise = chk2 $ next i
However, I doubt this is what you want, since it means all your results will be Right.
I'm not sure how to do what you want, because I'm not sure what you want.
What does a list result mean? What does a non-list result mean?
What you probably want to do is pattern match the result of the recursion, transforming Right pair -> Left [pair], perhaps appending some other result to the front.
As an example, I'll construct a recursive function with a similar type signature. Let foo be a function that takes a list of integers, and:
if the first element of the list is the maximum of the whole list, returns that element
otherwise, return a subsequence of the list, where each is the maximum of all the elements between it and the next element in the subsequence (or the end)
To do this:
foo :: [Integer] -> Either [Integer] Integer
foo [] = Left []
foo (x:xs) = case foo xs of
Left ys -> if all (<=x) ys
then Right x
else let (_,ys') = break (>x) ys in Left (x:ys')
Right y -> if x >= y
then Right x
else Left [x,y]
Note how I use case to pattern match on the result of the recursive call to foo.
To solve Euler #4, yours seems to be a very awkward style for Haskell. It's usually a bad idea to try and "port" code from other languages into Haskell, since the paradigm for Haskell is so very different.
You'll find a very clean, sensible solution to Euler #4 that uses list comprehensions at the Haskell Wiki. Certainly not the only solution, but it is at least 20x as readable as your current code. No offense.
I (and tons of other Haskellers) highly recommend Learn You a Haskell and Real World Haskell for learning how to approach problems the Haskell way, which in my experience is usually to create small, simple helper methods and compose them into a solution.