Haskell function incompatible type and definition - haskell

I'm trying to understand this function (taken from here)
escape :: String -> String
escape =
let
escapeChar c =
case c of
'<' -> "<"
'>' -> ">"
_ -> [c]
in
concat . map escapeChar
My questions are:
According to the type, escape is a function that takes a String. But it seems that in in the fuction definition it does not receive any argument. How does this work?
What is the relationship between escapeChar and c? How is that relationship established? Does c coming right after escapeChar have a meaning?

Would it be easier if escapeChar were a top-level definition using pattern matching:
escape :: String -> String
escape = concatMap escapeChar
escapeChar :: Char -> String
escapeChar '<' = "<"
escapeChar '>' = ">"
escapeChar ch = [ch]
[ch] is a singleton list, it turns ch :: Char into a [ch] :: String.
In Haskell you can remove/add an argument from/to each side (eta conversion). escape is the eta reduced form of
escape :: String -> String
escape str = concatMap escapeChar str
Just like, if you wanted to define a synonym for (+) you have equivalent ways of writing it. I feel like the add = (+) is clearest, you are identifying the two functions. The arguments are the same on both sides so we don't specify them.
add :: Int -> Int -> Int
add = (+)
add a = (+) a
add a = (a +)
add a b = (+) a b
add a b = a + b
These are equivalent ways of writing escape:
escape = concat . map escapeChar
escape str = concat (map escapeChar str)

According to the type, escape is a function that takes a String. But it seems that in in the fuction definition it does not receive any argument. How does this work?
concat . map escape returns a function. That function will take a string and process it.
What is the relationship between escapeChar and c? How is that relationship established? Does c coming right after escapeChar have a meaning?
Yes, it is the first (and only) parameter of the function. It is a Character, and the escapeChar function maps that Char on a String. The let clause thus defines a function escapeChar :: Char -> String that will then be used in concat . map escape (or perhaps better concatMap escape). This will map each Char of the given String to a substring, and these are then concatenated together as a result.

the map function has a signature (a -> b) -> ([a] -> [b]) this means that the map function takes in a function(the escapeChar function) and returns a function that converts a list using that function(the escapeChar function). map escapeChar returns a function that converts a string using the escapeChar function on each character in the string.

Related

Haskell: Parsing String to Custom Type

I have declared a type:
type Foo = (Char, Char, Char)
And want to be able to parse a 3 letter string "ABC" to produce an output Foo with each of ABC as the three attributes of the type.
My current attempt is;
parseFoo :: String → Maybe Foo
parseFoo str = f where
f (a, _, _) = str[0]
f (_, b, _) = str[1]
f (_, _, c) = str[2]
This is returning an error:
Illegal operator ‘→’ in type ‘String → Maybe Foo’
Use TypeOperators to allow operators in types
My question is:
How do I prevent this error on compilation?
Am I even on the right track?
If I understand it the correct way, you want to store the first three characters of a string into a type Foo (which is an alias for a 3-tuple that contains three Chars).
The signature seems correct (it is good practice to return a Maybe if something can go wrong, and here it is possible that the string contains less than three characters). A problem hwever is that you write an arrow character → whereas signatures in Haskell usse -> (two ASCII characters, a dash and a greater than symbol).
So we can define the signature as:
parseFoo :: String -> Maybe Foo
Now the second problem is that you here define a function f that maps Foos to Strings, so the reverse. You also make use of a syntax that is frequently used for indexing in languages of the C/C++/C#/Java programming language family, but indexing in Haskell is done with the (!!) operator, and since you define the function in reverse, it will not help.
A string is a list of Chars, so:
type String = [Char]
We can thus define two patterns:
a list with three (or more) characters; and
a list with less than three characters.
For the former, we return a 3-tuple with these characters (wrapped in a Just), for the latter we return Nothing:
parseFoo :: String -> Maybe Foo
parseFoo (a:b:c:_) = Just (a, b, c)
parseFoo _ = Nothing
Or if we do not want to parse strings with more than three characters successfully:
parseFoo :: String -> Maybe Foo
parseFoo [a, b, c] = Just (a, b, c)
parseFoo _ = Nothing

composition and partial application on haskell [duplicate]

If I want to add a space at the end of a character to return a list, how would I accomplish this with partial application if I am passing no arguments?
Also would the type be?
space :: Char -> [Char]
I'm having trouble adding a space at the end due to a 'parse error' by using the ++ and the : operators.
What I have so far is:
space :: Char -> [Char]
space = ++ ' '
Any help would be much appreciated! Thanks
Doing what you want is so common in Haskell it's got its own syntax, but being Haskell, it's extraordinarily lightweight. For example, this works:
space :: Char -> [Char]
space = (:" ")
so you weren't far off a correct solution. ([Char] is the same as String. " " is the string containing the character ' '.) Let's look at using a similar function first to get the hang of it. There's a function in a library called equalFilePath :: FilePath -> FilePath -> Bool, which is used to test whether two filenames or folder names represent the same thing. (This solves the problem that on unix, mydir isn't the same as MyDir, but on Windows it is.) Perhaps I want to check a list to see if it's got the file I want:
isMyBestFile :: FilePath -> Bool
isMyBestFile fp = equalFilePath "MyBestFile.txt" fp
but since functions gobble their first argument first, then return a new function to gobble the next, etc, I can write that shorter as
isMyBestFile = equalFilePath "MyBestFile.txt"
This works because equalFilePath "MyBestFile.txt" is itself a function that takes one argument: it's type is FilePath -> Bool. This is partial application, and it's super-useful. Maybe I don't want to bother writing a seperate isMyBestFile function, but want to check whether any of my list has it:
hasMyBestFile :: [FilePath] -> Bool
hasMyBestFile fps = any (equalFilePath "MyBestFile.txt") fps
or just the partially applied version again:
hasMyBestFile = any (equalFilePath "MyBestFile.txt")
Notice how I need to put brackets round equalFilePath "MyBestFile.txt", because if I wrote any equalFilePath "MyBestFile.txt", then filter would try and use just equalFilePath without the "MyBestFile.txt", because functions gobble their first argument first. any :: (a -> Bool) -> [a] -> Bool
Now some functions are infix operators - taking their arguments from before and after, like == or <. In Haskell these are just regular functions, not hard-wired into the compiler (but have precedence and associativity rules specified). What if I was a unix user who never heard of equalFilePath and didn't care about the portability problem it solves, then I would probably want to do
hasMyBestFile = any ("MyBestFile.txt" ==)
and it would work, just the same, because == is a regular function. When you do that with an operator function, it's called an operator section.
It can work at the front or the back:
hasMyBestFile = any (== "MyBestFile.txt")
and you can do it with any operator you like:
hassmalls = any (< 5)
and a handy operator for lists is :. : takes an element on the left and a list on the right, making a new list of the two after each other, so 'Y':"es" gives you "Yes". (Secretly, "Yes" is actually just shorthand for 'Y':'e':'s':[] because : is a constructor/elemental-combiner-of-values, but that's not relevant here.) Using : we can define
space c = c:" "
and we can get rid of the c as usual
space = (:" ")
which hopefully make more sense to you now.
What you want here is an operator section. For that, you'll need to surround the application with parentheses, i.e.
space = (: " ")
which is syntactic sugar for
space = (\x -> x : " ")
(++) won't work here because it expects a string as the first argument, compare:
(:) :: a -> [a] -> [a]
(++) :: [a] -> [a] -> [a]

Why does this function work even though the argument is missing?

I'm trying to understand the following piece of code:
import Data.Char (ord)
encodeInteger :: String -> Integer
encodeInteger = read . concatMap ch
where ch c = show (ord c)
But I don't see how this can work when encodeInteger is defined as a function that takes a string, but in the second line, the function is implemented without that string argument.
Also, concatMap (according to hoogle), takes a function and a list, but only the function ch is provided.
Why does this code still work? Is the argument somehow magically passed? Has it something to do with currying?
edit: And why doesn't it work to change it like this:
encodeInteger :: String -> Integer
encodeInteger a = read . concatMap ch a
where ch c = show (ord c)
Basically defining a function
f = g
is the same as defining the function
f x = g x
In your specific case, you can use
encodeInteger a = (read . concatMap ch) a
to define your function. The parentheses are needed, otherwise it is parsed as
encodeInteger a = (read) . (concatMap ch a)
and concatMap ch a is not a function and can not be composed. At most you could write
encodeInteger a = read (concatMap ch a)
-- or
encodeInteger a = read $ concatMap ch a
About "why concatMap ch takes only one argument?". This is a partial application, which is very common in Haskell. If you have
f x y z = x+y+z
you can call f with fewer arguments, and obtain as the result a function of the remaining arguments. E.g., f 1 2 is the function taking z and returning 1+2+z.
Concretely, thanks to Currying, there's no such a thing as a function taking two or more arguments. Every function always takes only one argument. When you have a function like
foo :: Int -> Bool -> String
then foo takes one argument, an Int. It returns a function, which takes a Bool and finally returns a String. You can visualize this by writing
foo :: Int -> (Bool -> String)
Anyway, if you look up currying and partial application, you will find plenty of examples.
encodeInteger :: String -> Integer
encodeInteger = read.concatMap (\char -> show $ ord char)
The encodeInteger on the left hand side (LHS) of "=" is a name; it refers to the function on the right hand side (RHS) of "=". Both have the function type: String -> Integer. Both take a list of characters and produces an integer. Haskell enables us to express such function equality without specifying formal arguments (a style known as point-free).
Now, let's look at the RHS. The (.) operator composes two functions together. The composed function takes a string as its input from concatMap and produces an integer coming out of read as the output of the composed function.
concatMap itself takes 2 inputs, but we need to leave out the second one for the composed function, which requires a string as its input. We achieve this by partially applying concatMap, including only its first argument.

Haskell list type conversion

Support I have a list of type [Char], and the values enclosed are values of a different type if I remove their quotations which describe them as characters. e.g. ['2','3','4'] represents a list of integers given we change their type.
I have a similar but more complicated requirement, I need to change a [Char] to [SomeType] where SomeType is some arbitrary type corresponding to the values without the character quotations.
Assuming you have some function foo :: Char -> SomeType, you just need to map this function over your list of Char.
bar :: [Char] -> [SomeType]
bar cs = map foo cs
I hope I get this correctly and there is a way (if the data-constructors are just one-letters too) - you use the auto-deriving for Read:
data X = A | B | Y
deriving (Show, Read)
parse :: String -> [X]
parse = map (read . return)
(the return will just wrap a single character back into a singleton-list making it a String)
example
λ> parse "BAY"
[B,A,Y]

Haskell: Escaped character from character

I'm writing a parsec parser which reads in strings and converts escaped characters, as part of exercise 3 here.
For that exercise I am using this function:
escapedCharFromChar :: Char -> Char
escapedCharFromChar c = read $ concat ["'\\",[c],"'"]
I am not to impressed with the use of read to convert the character x into the escape character with the name x. Can anyone suggest a more elegant function of type Char -> Char to do this?
One way is to lay out the cases exhaustively:
charFromEscape :: Char -> Char
charFromEscape 'n' = '\n'
charFromEscape 't' = '\t'
--- ... --- Help!
You could also use lookup:
-- this import goes at the top of your source file
import Data.Maybe (fromJust)
charFromEscape :: Char -> Char
charFromEscape c = fromJust $ lookup c escapes
where escapes = [('n', '\n'), ('t', '\t')] -- and so on
The fromJust bit may look strange. The type of lookup is
lookup :: (Eq a) => a -> [(a, b)] -> Maybe b
which means for a value of some type over which equality is defined and a lookup table, it wants to give you the corresponding value from the lookup table—but your key isn't guaranteed to be present in the table! That's the purpose of Maybe, whose definition is
data Maybe a = Just a | Nothing
With fromJust, it assumes you got Just something (i.e., c has an entry in escapes), but this will fall apart when that assumption is invalid:
ghci> charFromEscape 'r'
*** Exception: Maybe.fromJust: Nothing
These examples will move you along in the exercise, but it's clear that you'd like better error handling. Also, if you expect the lookup table to be large, you may want to look at Data.Map.
read (or rather, Text.Read.Lex.lexCharE) is how you get at GHC's internal table, which is defined as:
lexEscChar =
do c <- get
case c of
'a' -> return '\a'
'b' -> return '\b'
'f' -> return '\f'
'n' -> return '\n'
'r' -> return '\r'
't' -> return '\t'
'v' -> return '\v'
'\\' -> return '\\'
'\"' -> return '\"'
'\'' -> return '\''
_ -> pfail
Eventually, you have to define the semantics somewhere. You can do it in your program, or you can reuse GHC's.
I just used pattern matching for the few escapes I cared about - i.e. 't' -> '\t'etc. The solution other readers suggested were similar. Not very generic, but very straight-forward.
You should consider implementing a proper Parser Char function instead of a Char -> Char.
(Or, if you're doing that anyway, consider using a Char -> Maybe Char instead.)
The Char -> Char approach only works if escape sequences consist of only a backslash and a single other character. Some languages have more complex character escapes that consist of a longer sequence of characters. For example, C++ supports multi-character escape sequences such as \u005C (which represents the unicode code point U+005C).
parseEscapeSequence :: Parser Char
parseEscapeSequence = do
c <- get
case c of
'\' -> return '\\'
'0' -> Just '\0'
't' -> return '\t'
'f' -> return '\f'
'r' -> return '\r'
'n' -> return '\n'
-- ...
'u' -> parseUnicodeEscape4
'U' -> parseUnicodeEscape8
-- ...
_ -> fail "Unrecognised escape sequence"
Whereby parseUnicodeEscape4 and parseUnicodeEscape8 would each parse a fixed number of hexadecimal digits and convert them into a unicode character, likely by first converting the digits into integers in the 0..15 range, then combining those 'nibbles' into a larger integer, and then converting that integer into a unicode character.
You could alternatively offload the simple escape sequences to another function that does pattern matching, but that function should ideally have a type of Char -> Maybe Char, to allow for proper error reporting.
parseEscapeSequence :: Parser Char
parseEscapeSequence = do
c <- get
case c of
-- ...
'u' -> parseUnicodeEscape4
'U' -> parseUnicodeEscape8
-- ...
_ ->
case maybeCharFromEscape c of
Just result -> return result
Nothing -> fail "Unrecognised escape sequence"
maybeCharFromEscape :: Char -> Maybe Char
maybeCharFromEscape c =
case c of
'\' -> Just '\\'
'0' -> Just '\0'
't' -> Just '\t'
'f' -> Just '\f'
'r' -> Just '\r'
'n' -> Just '\n'
_ -> Nothing
For the maybeCharFromEscape function you could alternatively implement it via lookup or a Map (as other answers point out), but even then you're still going to have to explicitly write down all the possibilities and the result might be less efficient (though you may find it more readable).

Resources