In Haskell, I got this string "bbbbffff", and I want to get a list in this form:
['b','b','b','b','f','f','f','f']
I think that I can use map, but sincerely, I don't know how to begin, and are a lot of things that I do not understand in Haskell.
Thanks in advance.
By default, a String is already a [Char] (see specification):
A string is a list of characters:
type String = [Char]
They simply don't print as ['b','b','b',...] because [Char] and String is the same type and therefore indistinguishable and must be shown the same way. Indeed, if you input your list you'll see it formatted as a string:
Prelude> 42
42
Prelude> [1,2,3]
[1,2,3]
Prelude> ['b','b','b','b','f','f','f','f']
"bbbbffff"
This means that you can immediately pass it to any list function, without having to do anything with it:
myLength :: [Char] -> Int
myLength (c:rest) = 1 + myLength rest
myLength [] = 0
-- Prints 11
main = print (myLength "hello world")
There are other textual data types like Data.Text, but these are for more advanced use and must be explicitly enabled and used.
Related
I'm writing a function that takes arbitrary lists and compares them to see if one is a sublist of the other. For stdin, I wanted to ask the user for two lists but I can't figure out a way to accept an arbitrary type. Here is my code so far:
1 main :: IO ()
2 main = do
3 l1 <- getLine
4 l2 <- getLine
5 print $ sublist (read l1 :: [Int]) (read l2:: [Int])
6
7 sublist :: Eq a => [a] -> [a] -> Bool
8 sublist b p = any ((b ==) . take len) . takeWhile ((len<=) . length) $ iterate tail p
9 where len = length b
My main issue is line 5 where I have to pick a type for read.
Some examples of input and output I would want to have while I can only currently support one at a time:
>>> [1,2,3]
[1,2,3,4,5]
True
>>> ["a", "bc"]
["xy", "b", "bc"]
False
>>> [True, False, True]
>>> [False, True, False, True]
True
-- And even nested types
>>> [[1], [2,3]]
[[2,4], [1], [2,3], [4]
True
Any help would be greatly appreciated!
read has to know in advance what kind of thing it is reading - that's just the way it works.
It is not the case that read looks at the string to determine what type to return. For instance consider:
read "1" :: Float
read "1" :: Int
The first read will return a Float (1.0) and the second an Int (1) even though the string being read is exactly the same.
You might think this is different from other languages, such as Python, where you can eval "[1,2,3]" and get a list and eval "5" to get a number and you don't have to tell eval what kind of thing to return. However, Haskell's answer to that is those languages are really only dealing with one type which is a sum type like:
data PyVal = PyNum Int
| PyStr String
| PyList [ PyVal ]
| PyDict [ (PyStr, PyVal) ]
| ...
Hence the universe of possible expressions is closed. So, actually, eval knows what kind of thing it is reading. In Haskell you can always add new types and therefore new reader and show functions.
Your fundamental problem is Haskell-independent. Simply giving someone two string representations of values is not enough to determine equality. You have to tell that person what the interpretation of those values is supposed to be since one string can be interpreted many ways.
For example, let's say I give you the following inputs
>>> ['a', 'b']
['A', 'B']
What should you return? If I mean this to be interpreted using standard case-sensitive characters, then I should get back False. If on the other hand I'm using case-insensitive characters (e.g. as provided by this package) then I should get back True. Just giving me the string representations is ambiguous.
If what you care about is the string representation itself, then just read your values into lists of strings and use sublist on those. If you do care about the interpretation of that string, then you have to either allow the user to specify that interpretation, or specify that interpretation in code somehow (of which #ErikR's ADT encoding and your type annotations are two possibilities).
I have a list of strings:
[" ix = index"," ctr = counter"," tbl = table"]
and I want to create a tuple from it like:
[("ix","index"),("ctr","counter"),("tbl","table")]
I even tried:
genTuple [] = []
genTuples (a:as)= do
i<-splitOn '=' a
genTuples as
return i
Any help would be appriciated
Thank you.
Haskell's type system is really expressive, so I suggest to think about the problem in terms of types. The advantage of this is that you can solve the problem 'top-down' and the whole program can be typechecked as you go, so you can catch all kinds of errors early on. The general approach is to incrementally divide the problem into smaller functions, each of which remaining undefined initially but with some plausible type.
What you want is a function (let's call it convert) which take a list of strings and generates a list of tuples, i.e.
convert :: [String] -> [(String, String)]
convert = undefined
It's clear that each string in the input list will need to be parsed into a 2-tuple of strings. However, it's possible that the parsing can fail - the sheer type String makes no guarantees that your input string is well formed. So your parse function maybe returns a tuple. We get:
parse :: String -> Maybe (String, String)
parse = undefined
We can immediately plug this into our convert function using mapMaybe:
convert :: [String] -> [(String, String)]
convert list = mapMaybe parse list
So far, so good - but parse is literally still undefined. Let's say that it should first verify that the input string is 'valid', and if it is - it splits it. So we'll need
valid :: String -> Bool
valid = undefined
split :: String -> (String, String)
split = undefined
Now we can define parse:
parse :: String -> Maybe (String, String)
parse s | valid s = Just (split s)
| otherwise = Nothing
What makes a string valid? Let's say it has to contain a = sign:
valid :: String -> Bool
valid s = '=' `elem` s
For splitting, we'll take all the characters up to the first = for the first tuple element, and the rest for the second. However, you probably want to trim leading/trailing whitespace as well, so we'll need another function. For now, let's make it a no-op
trim :: String -> String
trim = id
Using this, we can finally define
split :: String -> (String, String)
split s = (trim a, trim (tail b))
where
(a, b) = span (/= '=') s
Note that we can safely call tail here because we know that b is never empty because there's always a separator (that's what valid verified). Type-wise, it would've been nice to express this guarantee using a "non-empty string" but that may be a bit overengineered. :-)
Now, there are a lot of solutions to the problem, this is just one example (and there are ways to shorten the code using eta reduction or existing libraries). The main point I'm trying to get across is that Haskell's type system allows you to approach the problem in a way which is directed by types, which means the compiler helps you fleshing out a solution from the very beginning.
You can do it like this:
import Control.Monda
import Data.List
import Data.List.Split
map ((\[a,b] -> (a,b)) . splitOn "=" . filter (/=' ')) [" ix = index"," ctr = counter"," tbl = table"]
First post here, please go easy on me. Found several threads with similar issues, none of those applied directly or if one did, the execution was far enough over my head.
If i have code p=['1','2','3','4'] that stores digits as characters in p, how do i create a list q that can equal [1,2,3,4]?
I've been trying all sorts of things, mostly arriving at my q being out of scope or any function i try to convert Char -> Int lacking accompanying binding.
I seem to find indication everywhere that there is such a thing as digitToInt, where digitToInt '1' should yield an output of 1 but i apparently lack bindings, even with the exact input from this page:
http://zvon.org/other/haskell/Outputchar/digitToInt_f.html
At this point reading more things i am just becoming more confused. Please help with either a viable solution that might show me where i'm messing up or with an explanation why this digitToInt :: Char -> Int seems to not work for me in the slightest.
Thank you.
digitToInt is something that already exists. It used to live in the Char module but now it lives in Data.Char, so we have to import Data.Char to use it.
Prelude> import Data.Char
Prelude Data.Char> digitToInt '1'
1
You can use digitToInt on every element of a list with map digitToInt. map :: (a->b) -> [a] -> [b] applies a function (a->b) to each element of a list of as, [a] to get a list of bs, [b].
Prelude Data.Char> map digitToInt ['1', '2', '3', '4']
[1,2,3,4]
Lacks an accompanying binding
You don't need to define digitToInt or other imports by writing it's type signature digitToInt :: Char -> Int. A signature written without a binding like that
alwaysSeven :: Char -> Int
will give the following error.
The type signature for `alwaysSeven' lacks an accompanying binding
You only provide a type signature when it comes right before a declaration.
alwaysSeven :: Char -> Int
alwaysSeven x = 7
Without importing anything you can also use a very simply trick, and push ((:[])) the character in an empty list (making a singleton list) before reading the value:
map (read . (:[])) "1234"
This will need the context of the type of the list to be deducible, but it will work for any type you want without modifications. Otherwise you'll need to specify the type yourself:
(map (read . (:[])) "1234") :: [Int]
-- [1,2,3,4]
(map (read . (:[])) "1234") :: [Double]
-- [1.0,2.0,3.0,4.0]
I've just started trying to learn haskell and functional programming. I'm trying to write this function that will convert a binary string into its decimal equivalent. Please could someone point out why I am constantly getting the error:
"BinToDecimal.hs":19 - Syntax error in expression (unexpected `}', possibly due to bad layout)
module BinToDecimal where
total :: [Integer]
total = []
binToDecimal :: String -> Integer
binToDecimal a = if (null a) then (sum total)
else if (head a == "0") then binToDecimal (tail a)
else if (head a == "1") then total ++ (2^((length a)-1))
binToDecimal (tail a)
So, total may not be doing what you think it is. total isn't a mutable variable that you're changing, it will always be the empty list []. I think your function should include another parameter for the list you're building up. I would implement this by having binToDecimal call a helper function with the starting case of an empty list, like so:
binToDecimal :: String -> Integer
binToDecimal s = binToDecimal' s []
binToDecimal' :: String -> [Integer] -> Integer
-- implement binToDecimal' here
In addition to what #Sibi has said, I would highly recommend using pattern matching rather than nested if-else. For example, I'd implement the base case of binToDecimal' like so:
binToDecimal' :: String -> [Integer] -> Integer
binToDecimal' "" total = sum total -- when the first argument is the empty string, just sum total. Equivalent to `if (null a) then (sum total)`
-- Include other pattern matching statements here to handle your other if/else cases
If you think it'd be helpful, I can provide the full implementation of this function instead of giving tips.
Ok, let me give you hints to get you started:
You cannot do head a == "0" because "0" is String. Since the type of a is [Char], the type of head a is Char and you have to compare it with an Char. You can solve it using head a == '0'. Note that "0" and '0' are different.
Similarly, rectify your type error in head a == "1"
This won't typecheck: total ++ (2^((length a)-1)) because the type of total is [Integer] and the type of (2^((length a)-1)) is Integer. For the function ++ to typecheck both arguments passed to it should be list of the same type.
You are possible missing an else block at last. (before the code binToDecimal (tail a))
That being said, instead of using nested if else expression, try to use guards as they will increase the readability greatly.
There are many things we can improve here (but no worries, this is perfectly normal in the beginning, there is so much to learn when we start Haskell!!!).
First of all, a string is definitely not an appropriate way to represent a binary, because nothing prevents us to write "éaldkgjasdg" in place of a proper binary. So, the first thing is to define our binary type:
data Binary = Zero | One deriving (Show)
We just say that it can be Zero or One. The deriving (Show) will allow us to have the result displayed when run in GHCI.
In Haskell to solve problem we tend to start with a more general case to dive then in our particular case. The thing we need here is a function with an additional argument which holds the total. Note the use of pattern matching instead of ifs which makes the function easier to read.
binToDecimalAcc :: [Binary] -> Integer -> Integer
binToDecimalAcc [] acc = acc
binToDecimalAcc (Zero:xs) acc = binToDecimalAcc xs acc
binToDecimalAcc (One:xs) acc = binToDecimalAcc xs $ acc + 2^(length xs)
Finally, since we want only to have to pass a single parameter we define or specific function where the acc value is 0:
binToDecimal :: [Binary] -> Integer
binToDecimal binaries = binToDecimalAcc binaries 0
We can run a test in GHCI:
test1 = binToDecimal [One, Zero, One, Zero, One, Zero]
> 42
OK, all fine, but what if you really need to convert a string to a decimal? Then, we need a function able to convert this string to a binary. The problem as seen above is that not all strings are proper binaries. To handle this, we will need to report some sort of error. The solution I will use here is very common in Haskell: it is to use "Maybe". If the string is correct, it will return "Just result" else it will return "Nothing". Let's see that in practice!
The first function we will write is to convert a char to a binary. As discussed above, Nothing represents an error.
charToBinary :: Char -> Maybe Binary
charToBinary '0' = Just Zero
charToBinary '1' = Just One
charToBinary _ = Nothing
Then, we can write a function for a whole string (which is a list of Char). So [Char] is equivalent to String. I used it here to make clearer that we are dealing with a list.
stringToBinary :: [Char] -> Maybe [Binary]
stringToBinary [] = Just []
stringToBinary chars = mapM charToBinary chars
The function mapM is a kind of variation of map which acts on monads (Maybe is actually a monad). To learn about monads I recommend reading Learn You a Haskell for Great Good!
http://learnyouahaskell.com/a-fistful-of-monads
We can notice once more that if there are any errors, Nothing will be returned.
A dedicated function to convert strings holding binaries can now be written.
binStringToDecimal :: [Char] -> Maybe Integer
binStringToDecimal = fmap binToDecimal . stringToBinary
The use of the "." function allow us to define this function as an equality with another function, so we do not need to mention the parameter (point free notation).
The fmap function allow us to run binToDecimal (which expect a [Binary] as argument) on the return of stringToBinary (which is of type "Maybe [Binary]"). Once again, Learn you a Haskell... is a very good reference to learn more about fmap:
http://learnyouahaskell.com/functors-applicative-functors-and-monoids
Now, we can run a second test:
test2 = binStringToDecimal "101010"
> Just 42
And finally, we can test our error handling system with a mistake in the string:
test3 = binStringToDecimal "102010"
> Nothing
I want to be able to type the following in ghci:
map showTypeSignature [(+),(-),show]
I want ghci to return the following list of Strings:
["(+) :: Num a => a -> a -> a","(-) :: Num a => a -> a -> a","show :: Show a => a -> String"]
Naturally, the first place that I run into trouble is that I cannot construct the first list, as the type signatures of the functions don't match. What can I do to construct such a list? How does ghci accomplish the printing of type signatures? Where is the ghci command :t defined (its source)?
What you're asking for isn't really possible. You cannot easily determine the type signature of a Haskell term from within Haskell. At run-time, there's hardly any type information available. The GHCi command :t is a GHCi command, not an interpreted Haskell function, for a reason.
To do something that comes close to what you want you'll have to use GHC itself, as a library. GHC offers the GHC API for such purposes. But then you'll not be able to use arbitrary Haskell terms, but will have to start with a String representation of your terms. Also, invoking the compiler at run-time will necessarily produce an IO output.
kosmikus is right, this doesn't really work out. And shouldn't, the static type system is one of Haskell's most distinguishing features!
However, you can emulate this for monomorphic functions quite well using the Dynamic existential:
showTypeSignature :: Dynamic -> String
showTypeSignature = show . dynTypeRep
Prelude Data.Dynamic> map showTypeSignature [toDyn (+), toDyn (-), toDyn (show)]
["Integer -> Integer -> Integer","Integer -> Integer -> Integer","() -> [Char]"]
As you see ghci had to boil the functions down to monomorphic type here for this to work, which particularly for show is patently useless.
The answers you have about why you can't do this are very good, but there may be another option. If you don't care about getting a Haskell list, and just want to see the types of a bunch of things, you can define a custom GHCi command, say :ts, that shows you the types of a list of things; to wit,
Prelude> :ts (+) (-) show
(+) :: Num a => a -> a -> a
(-) :: Num a => a -> a -> a
show :: Show a => a -> String
To do this, we use :def; :def NAME EXPR, where NAME is an identifier and EXPR is a Haskell expression of type String -> IO String, defines the GHCi command :NAME. Running :NAME ARGS evaluates EXPR ARGS to produce a string, and then runs the resulting string in GHCi. This is less confusing than it sounds. Here's what we do:
Prelude> :def ts return . unlines . map (":type " ++) . words
Prelude> :ts (+) (-) show
(+) :: Num a => a -> a -> a
(-) :: Num a => a -> a -> a
show :: Show a => a -> String
What's going on? This defines :ts to evaluate return . unlines . map (":t " ++) . words, which does the following:
words: Takes a string and splits it on whitespace; e.g., "(+) (-) show" becomes ["(+)", "(-)", "show"].
map (":type " ++): Takes each of the words from before and prepends ":type "; e.g., ["(+)", "(-)", "show"] becomes [":type (+)", ":type (-)", ":type show"]. Notice that we now have a list of GHCi commands.
unlines: Takes a list of strings and puts newlines after each one; e.g., [":type (+)", ":type (-)", ":type show"] becomes ":type (+)\n:type (-)\n:type show\n". Notice that if we pasted this string into GHCi, it would produce the type signatures we want.
return: Lifts a String to an IO String, because that's the type we need.
Thus, :ts name₁ name₂ ... nameₙ will evaluate :type name₁, :type name₂, …, :type nameₙ in succession and prints out the results. Again, you can't get a real list this way, but if you just want to see the types, this will work.