Ok, I'm trying to learn haskell. Couple of times I've posted questions that has been down voted because I can't explain well what I'm trying to achieve, but I'm going to try again with a new question.
I find a piece of code that I want to modify a bit. Here it is:
import qualified Data.Map as M
type Dict = M.Map String String
translate :: Dict -> [String] -> [String]
translate dict words = map trans words
where
trans :: String -> String
trans w =
case M.lookup w dict of
(Just w') -> w'
Nothing -> "whatchamacallit"
testTranslation :: Dict -> IO ()
testTranslation dict = do
print $ translate dict ["where", "is", "the", "colosseum"]
testInsertion :: Dict -> IO Dict
testInsertion dict = do
return $ M.insert "colosseum" "colosseo" dict
main =
let dict = M.fromList [("where", "dove"), ("is", "e"), ("the", "il")]
in do
testTranslation dict
dict' <- testInsertion dict
testTranslation dict'
putStrLn "The original dictionary is unchanged:"
testTranslation dict
In short: It will replace the elems where with dove, is with e and e.t.c but it is using Data.Map.
So my question is - Is there a way to do the same thing without using Data.Map
You can use lists as dictionaries. Of course, it will not be practical for big dictionaries, because the lookup is O(N).
Here is the type signature of the list lookup:
lookup :: Eq α => α -> [(α, β)] -> Maybe β
This tells the following:
Given some item of type a and a list of tuples (a,b), the function will return Nothing or Just someb, where someb is of type b.
As you could easily find out if you played around a bit with that function in ghci, it will return the second value in the tuple if the first part of the tuple equals the key.
Hence:
lookup 42 [(1, "one"), (42, "it"), (2, "bar")]
should be
Just "it"
whereas
lookup 77 [(1, "one"), (42, "it"), (2, "bar")]
should be
Nothing
You can try it in GHCi and it should ot be too hard to get rid of Data.Map in your program. As far as I can see, there are just 3 small changes to do (not counting the dropping of the import).
Related
I'm new at haskell and I'm trying to print the elements of a list in a same line . For example:
[1,2,3,4] = 1234
If elements are Strings I can print it with mapM_ putStr ["1","2","3","\n"]
but they aren't.. Someone knows a solution to make a function and print that?
I try dignum xs = [ mapM_ putStr x | x <- xs ] too buts don't work ..
You can use show :: Show a => a -> String to convert an element (here an integer), to its textual representation as a String.
Furthermore we can use concat :: [[a]] -> [a] to convert a list of lists of elements to a list of elements (by concatenating these lists together). In the context of a String, we can thus use concat :: [String] -> String to join the numbers together.
So we can then use:
printConcat :: Show a => [a] -> IO ()
printConcat = putStrLn . concat . map show
This then generates:
Prelude> printConcat [1,2,3,4]
1234
Note that the printConcat function is not limited to numbers (integers), it can take any type of objects that are a type instance of the Show class.
How can I add a list to a list of lists? Say I want to add itemz to bagList, which is a list of lists. How can I do that?
bagList itemz = mappend bagList itemz
You might want to consider adding it at the front, this is faster:
bagItem bag item = item : bag
Also it looks like you're coming from an imperative mindset, the way you use bagList before and after the = is not quite right: the expressions before and after the = do not really represent the same construction. Before the = bagItem is used as a function, after the = it's used as some Monoid (which if itemz is a list would also need to be a list).
If you really do want to append the item (this will be slower, because the operation will require going all the way through the list to add the new item at the end, and the whole list will need to be reconstructed) you can do what Christoph suggests or you can go for a recursive formulation something like this:
appendItem :: a -> [a] -> [a]
appendItem i (x:xs) = x : appendItem i xs
appendItem i [] = i : []
If you both want to append and are also worried about performance, you should have a look at difference lists, for example look for the section on difference lists in this chapter in Learn You a Haskell.
Update
From the comments it seems what you are actually looking for is Maps. We can make a Map with each item as a key, and the number of occurrences as the value. In your case it seems this will be a Map String Int.
import Data.List (foldl')
import qualified Data.Map as M
bag :: M.Map String Int
bag = M.empty
addToBag :: M.Map String Int -> [String] -> M.Map String Int
addToBag = foldl' go
where go m i = M.insertWith (+) i 1 m
main = print $ addToBag bag ["a","b","c","a"]
-- fromList [("a",2), ("b", 1), ("c", 1)]
I have 2 lists which I am trying to fill will items. While reading from stdin, depending on the value of one of the things read, I want to append to a different list. Example,
import Control.Monad(replicateM)
main = do
n <- getLine
let l1 = [], l2 = []
in replicateM (read n) (getLine >>= (\line ->
case line of "Yes" ->
-- do something with line
-- and append value of that thing to l1
"No" ->
-- do something else
-- append this value to l2
putStrLn line))
I realise the above code has syntax errors and such, but hopefully you can see what I am trying to and suggest something.
This is the answer I came up with
While we are at it, can someone explain why this gives me an infinite list:
let g = []
let g = 1:g
-- g now contains an infinite list of 1's
This is what I finally came up with:
import Control.Monad(replicateM)
import Data.Either
getEither::[String] -> [Either Double Double]
getEither [] = []
getEither (line:rest) = let [n, h] = words line
fn = read f :: Double
e = case heist of "Yes" -> Left fn
"No" -> Right fn
in e : getEither rest
main = do
n <- getLine
lines <- replicateM (read n) getLine
let tup = partitionEithers $ getEither lines :: ([Double], [Double])
print tup
Not sure how fmap could have been used in this instance
Here is a short ghci session that may give you some ideas:
> :m + Control.Monad Data.Either
> partitionEithers <$> replicateM 3 readLn :: IO ([Int], [Bool])
Left 5
Right True
Left 7
([5,7],[True])
The answer to your second question is that let is recursive; so the two gs in let g = 1:g are referring to the same in-memory object.
You are thinking in term of mutable variables: you are "initializing" l1,l2 to the empty list and then reasoning about updating them with longer lists. This design works fine in imperative programming, but not so simply in pure functional programming since it involves mutation.
Now, even in pure functional programming we have ways to simulate mutation, through monads. For instance, once can achieve mutation here through IORefs or StateT IO. In this case, though, is would be an unnecessarily complex way to solve the task.
You want to append data to form two lists. You want to use replicateM, which is fine. The point is that replicateM will build just one list, instead of two. The question now is: how can we create a list which is easily split into two?
A first ugly attempt is to generate a list of tagged values, i.e. a list of pairs:
case line of
"Yes" -> let value = ... in
return ("for l1", value)
"No" -> let value = ... in
return ("for l2", value)
Doing this would make replicateM produce a list such as
[("for l1", value1), ("for l1", value2), ("for l2", value3), ...]
which we can then split into two lists.
The use of strings for tags looks however a bit unelegant, since a boolean would suffice:
case line of
"Yes" -> let value = ... in
return (True, value)
"No" -> let value = ... in
return (False, value)
An even better approach would be to use the Either a b type:
case line of
"Yes" -> let value1 = ... in
return (Left value1)
"No" -> let value2 = ... in
return (Right value2)
The nice consequence of the above is that value1 and value2 can even be of different types. The previous snippets forced them to share their type: since we build a list of pairs each pair must have the same type. The new list is now instead of type [Either a b] where a is the type of values to be put in l1, and b that for l2.
Once you get a [Either a b] you want to split it in [a] and [b]. As #DanielWagner suggests in his answer, you can exploit partitionEithers for this.
type Dictionary = [(String, String)]
dict :: Dictionary
dict = ("Deutsch", "English"):[]
insert :: Dictionary -> (String,String) -> Dictionary
insert dict entry = dict ++ [entry]
One thing that I didn't find about the way lists work: Is it somehow possible to overwrite the existing dict with the entry added in insert? Or is it necessary to, in the next step, always write out the list that was put out by insert?
insert [("German", "English"), ("Hallo", "hello")] ("Versuch", "try")
So far, this is the only way I have been able to add something to the new list without losing the previous entry. However, next on the list of things to implement is a search command, so I wonder if I'd also have to write this out in the search function.
The idea of functional programming is in general that your data is immutable. This means once you have created a list, you can NEVER change that list. But you can copy that list, make modifications to it, and keep that as well.
So when you have a list like so
test = [1,2,3]
We can modify this by adding 4 to the start:
test2 = 4 : test
: called the cons operator, puts an element in front of a list. Do note that x:xs (the same as doing [x]++xs) has a better performance than doing xs++[x]
So now we have two bindings, one of test to [1,2,3] and one of test2 to [4,1,2,3]
Hope this clarifies things
To give a full example:
type Dictionary = [(String, String)]
insert :: Dictionary -> (String,String) -> Dictionary
insert dict entry = dict ++ [entry]
dict0 = [ ("Deutsch", "English") ]
dict1 = insert dict0 ("Hallo", "hello")
dict2 = insert dict1 ("Versuch", "try")
If you're new to functional programming, I would recommend reading Learn You a Haskell for Great Good , which is a fantastic (and free) book on how to use Haskell -- and functional programming in general.
It's not too tough to do this
import Data.List (lookup)
insert :: Eq a => (a,b) -> [(a,b)] -> [(a,b)]
insert (a,b) [] = [(a,b)]
insert (a,b) ((c,d):rest) = if a == c
then (a,b) : rest
else (c,d) : insert (a,b) rest
---
dict :: [(String, String)]
dict = [("Deutsch", "English")]
If you can't use Data.List then you can define lookup by
lookup :: Eq a => a -> [(a,b)] -> Maybe b
lookup _ [] = Nothing
lookup k ((a,b):rest) = if k == a then Just b else lookup k rest
Now if you load up GHCI:
>> let dict' = insert ("Ein","One") dict
>> dict'
[("Deutsch","English"),("Ein","One")]
>> lookup "Ein" dict'
Just "One"
>> insert ("Deutsch", "Francais") dict'
[("Deutsch","Francais"),("Ein","One")]
If you want to replace an existing pair with the same key then you could write insert as:
insert :: Dictionary -> (String, String) -> Dictionary
insert [] p = [p]
insert ((dk, dv):ps) p#(k, v) | dk == k = p:ps
insert (p:ps) ip = p : (insert ps ip)
However if you are writing an association list, then you can simplify it by inserting new items at the front of the list:
insert :: Dictionary -> (String, String) -> Dictionary
insert = flip (:)
if you then search from the front of the list, it will find any values added more recently first.
In Haskell, most values are immutable, meaning that you can not change their value. This seems like a huge constraint at first, but in reality it makes it easier to reason about your program, especially when using multiple threads.
What you can do instead is continually call insert on the dictionary returned when you call insert, for example:
mainLoop :: Dictionary -> IO ()
mainLoop dict = do
putStrLn "Enter the German word:"
german <- getLine
putStrLn "Enter the English word:
english <- getLine
let newDict = insert dict (german, english)
putStrLn "Continue? (y/n)"
yesno <- getChar
if yesno == 'y'
then mainLoop newDict
else print newDict
main = do
One simply can't 'overwrite' anything in a pure language (outside of ST monad). If I understood your question correctly, you are looking for something like this:
insert :: Dictionary -> (String,String) -> Dictionary
insert [] b = [b] -- If this point is reached where wasn't matching key in dictionary, so we just insert a new pair
insert (h#(k, v) : t) b#(k', v')
| k == k' = (k, v') : t -- We found a matching pair, so we 'update' its value
| otherwise = h : insert t b
Problem
i have list of int as [123,123] which i required to be as [1,2,3,1,2,3]
Current Code
i tried out the following code using recursion
fat::[Int]->[Int]
fat [] = []
fat (a,b,c:xs) = a : b : c : fat xs
Conclusions
i have no idea how to acess values as '1' , '2 , '3 in a list [123,123] separetly
I suggest to use the digs function given in this answer on each element of your list. It splits an Int into a list of digits ([Int]). Then you just need to concatenate the resulting lists. This 'map and concatenate results' requirement is a perfect job for concatMap
fat :: [Int] -> [Int]
fat = concatMap digs
This gives:
*Main> fat [123,123]
[1,2,3,1,2,3]
Which is what you want, if I understood correctly.
splitNum :: Int -> [Int]
splitNum n | n <= 9 = [n]
| otherwise = (splitNum (n `div` 10)) ++ [n `mod` 10]
fat :: [Int] -> [Int]
fat x = concatMap splitNum x
splitNum is used to convert an Int to a [Int] by splitting it into the division by ten reminders and appending the resulting Int to the splitted rest (recursion!)
Now, having a function that converts numbers into lists, go through input, apply splitNum to any Number in the inner list and concat all resulting lists (list comprehension!)
As a new Haskell programmer I will give you my thoughts of this problem. Just because I think it's good to have many alternatives, especially from different people with different experience.
Here's my take on the problem:
For each item in the list, convert that item to a char list using read.
Send that char list into a function which converts each item of that list into an int, then return an list of ints.
Concat that list of ints into the main list.
To clarify:
[123, 234]
123 turns into ['1', '2', '3']
['1', '2', '3'] turns into [1, 2, 3]
[1, 2, 3] gets concat in the main list
the cycle repeats for 234.
The util function would look something like this:
import Char
charsToInts :: [Char] -> [Int]
charsToInts [] = []
charsToInts (x:xs) = digitToInt x : charsToInts xs
Coming from a imperative background that's how I would have solved it. Probably slower than just splitting the number mathematically, but I thought it would be interesting to show a alternative.
To pinpoint the problem bluntly, you have no idea how to access the digits separately because you do not understand Haskell types and pattern matching. Let me try to help dispel some of your misconceptions.
Let's look at your list:
[123, 123]
What is its type? It is clearly a list of ints, or [Int]. With lists, you can pattern match on the constructor :, known to lispers as "cons", or "list constructor". You put a single element on the left side of the :, and another list on the right side. The list on the right side can be the empty list [], which basically indicates the end of the list. Haskell provides "syntactic sugar" to make lists easier to write, but [123,456] actually gets desugared into 123:(456:[]). So when you pattern match (x:y:z), you can now see that x will be assigned 123 and y will be assigned 456. z will be the rest of the list after x and y; in this case only [] is left.
Now then, pattern matching with : works for lists. Ints are not lists, so you can't use : to pattern match on the digits of an Int. However, Strings are lists, because String is the same as [Char]. So if you turn your Int into a String then you can pattern match on each character.
map show [123, 123]
map applies a function to all elements of a list. show can take an Int and turn it into a String. So we map show over the list of Ints to get a list of Strings.
["123", "123"]
Now let's turn those Strings into lists of Ints. Since String is simply [Char], we will again make use of map.
map digitToInt "123" -- this requires that you import Data.Char (digitToInt)
This will give us [1,2,3]; each Char in the list is turned into an Int. This is what we want to do to each String in our list ["123", "123"]. We want to map digitToInt to each String. But we have a list of Strings. So what do we do? We map it!
map (map digitToInt) ["123", "123"]
This will give us [[1,2,3], [1,2,3]]. Almost what we wanted. Now we just have to flatten the list of list of Ints ([[Int]]) into just a list of Int ([Int]). How can we do that? Stop...Hoogle time! Hoogling [[a]] -> [a] we find the very first hit, concat, is exactly what we wanted.
Let's put it all together. First we do map show to get from [Int] to [String]. Then we do map (map digitToInt) to get from [String] to [[Int]]. Then we do concat to get from [[Int]] to [Int]. Then we'll just print it out!
import Data.Char (digitToInt)
main = print $ concat $ map (map digitToInt) $ map show $ [123, 123]
Now let's pull most of that out into a function fat
import Data.Char (digitToInt)
main = print $ fat [123, 123]
fat :: [Int] -> [Int]
fat xs = concat $ map (map digitToInt) $ map show $ xs
From here you could make it prettier in a few different ways. concat $ map is the same as concatMap, and since we map both (map digitToInt) and show in sequence, we can merge those. Also making it pointfree, we can end up with quite a terse definition:
fat = concatMap (map digitToInt . show)
For the sake of completeness, I wrote it as suggested by #Ancide
Implementation
fat' :: [Int] -> [Int]
fat' l = map (read) [[z] | z <- [x | k <- (map (show) l), x <- k]]
Explanation:
{- last result -} stands for the result of the last code explained.
map (show) l
This takes every element inside l and converts it to [String].
[x | k <- {- last result -}, x <- k]
While k goes through all elements inside the last result, x enumerates all character in each k. All those are added to a list. Now you have a String, respectively a [Char] with all digits next to each others.
[[z] | z <- {- last result -}]
This part takes each Char from the String and puts it into an empty String. Notice the [z] part! This make a list around z, which is (see above) the same as String. Now you have a list of String with a String for each digit.
map (read) {- last result -}
This takes every item in the last result and converts it back to Int and joins them to [Int]. Now you have a list of type [Int] of the wanted result.
Resumé
Although this implementation is possible, it's neither fast, due to all the type conversions, nor readable.
Playing around with the list monad I came up with this. Pretty much the same #Ankur's solution, except using the list monad:
fat :: [Int] -> [Int]
fat is = is >>= show >>= return . digitToInt
If you had two numbers, a and b then you could turn them into a single number by doing 10*a + b. The same principles apply for three.
It sounds like one way of doing this would be to splitEvery into lumps of three and then map a function to turn a list of three into a single number.
Does that help?
You need a function to convert Integer to string... which is obviously Show function
Another function to convert a Char to Integer which is "digitToInt" in module Char
And here we go :
fat::[Int]->[Int]
fat [] = []
fat ls = concat $ map (map digitToInt) (map show ls)
Please let me know if it works :)