I want to rewrite (or upgrade! :) ) my two functions, hist and sort, using fold-functions. But since I am only in the beginning of my Haskell-way, I can't figure out how to do it.
First of all, I have defined Insertion, Table and imported Data.Char:
type Insertion = (Char, Int)
type Table = [Insertion]
import Data.Char
Then I have implemented the following code for hist:
hist :: String -> Table
hist[] = []
hist(x:xs) = sortBy x (hist xs) where
sortBy x [] = [(x,1)]
sortBy x ((y,z):yzs)
| x == y = (y,z+1) : yzs
| otherwise = (y,z) : sortBy x yzs
And this one for sort:
sort :: Ord a => [a] -> [a]
sort [] = []
sort (x:xs) = paste x (sort xs)
paste :: Ord a => a -> [a] -> [a]
paste y [] = [y]
paste y (x:xs)
| x < y = x : paste y xs
| otherwise = y : x : xs
What can I do next? How can I use the fold-functions to implement them?
foldr f z on a list replaces the "cons" of the list (:) with f and the empty list [] with z.
This thus means that for a list like [1,4,2,5], we thus obtain f 1 (f 4 (f 2 (f 5 z))), since [1,4,2,5] is short for 1 : 4 : 2 : 5 : [] or more canonical (:) 1 ((:) 4 ((:) 2 ((:) 5 []))).
The sort function for example can be replaced with a fold function:
sort :: Ord a => [a] -> [a]
sort = foldr paste []
since sort [1,4,2,5] is equivalent to paste 1 (paste 4 (paste 2 (paste 5 []))). Here f thus takes as first parameter an element, and as second parameter the result of calling foldr f z on the rest of the list,
I leave hist as an exercise.
I got a problem with this exercise. I've been trying to solve it for a long time searching for stuff, but I am unable to.
Define functions:
addLnat :: [Int] -> [Int] -> [Int]
mulLnat :: [Int] -> [Int] -> [Int]
addLnat adds numbers from two arrays eg.
addLnat [4,5,6] [8,5,2] -> [2,1,9]
as [4+8 gives 2 carry 1, 5+5+1 gives 1 carry 1, 6+2+1 = 9]
Lnat, is a "list natural number", represented as a list of base-10 digits, least significant first. So the number 654 is [4,5,6].
What I got is:
addLnat :: [Int] -> [Int] -> [Int]
addLnat _ [] = []
addLnat [] _ = []
addLnat (x:xs) (y:ys) = (if (x+y) > 9 then x+y-10 else (x+y)):(addLnat xs ys)
I adding number and ignoring carry. Not sure how to solve it.
Any help would be much appreciated.
I have improved the solution as per user5402 comment, so created addLnat' cr xs ys, but when I what to pass carry as a parameter it fails to load - most probable that I am getting the syntax wrong:(
(cr is 0 only for now and it will be replaced by maths).
addLnat' c (x:xs) (y:ys) = d : addLnat' cr xs ys
where d = if c+x+y < 9 then x+y else c+x+y-((quot (c+x+y) 10)*10)
cr = 0
Any ideas?
I am not very good at haskell but maybe this can help ;
add::[Int]->[Int]->[Int]
add x y = add' 0 x y
There we define a function add that will use add' to add two lists The main idea is to "save" carry and carefully work with corner cases. Here carry is saved in "variable" rest
add'::Int->[Int]->[Int]->[Int]
add' 0 x [] = x
add' rest (x:[]) (y:[]) = [(r `mod` 10),(r `div` 10)]
where r = x+y+rest
add' y (x:xs) [] = add' (r `div` 10) ((r `mod` 10):xs) []
where r = x+y
add' rest (x:xs) (y:ys) = (r `mod` 10) : (add' (r `div` 10) xs ys)
where r = x+y+rest
List x must be bigger than list y but that's not a problem
add [5,7,8] [4,3,2] => [9,0,1,1] (correct)
add [1,2,3] [4,5,6] => [5,7,9,0] (correct)
You need to write a version of addLnat which accepts a carry parameter:
addLnat' c (x:xs) (y:ys) = d : addLnat c' xs ys
where d = if c+x+y > 9 then ... else ...
c' = ... the next carry bit ...
There are a lot more details and corner cases to consider, but this is the basic idea.
Finally,
addLnat xs ys = addLnat' 0 xs ys -- initially the carry is 0
With getIndex xs y I want the index of the first sublist in xs whose length is greater than y.
The output is:
[[],[4],[4,3],[3,5,3],[3,5,5,6,1]]
aufgabe6: <<loop>>
why getIndex does not work?
import Data.List
-- Die Sortierfunktion --
myCompare a b
| length a < length b = LT
| otherwise = GT
sortList :: [[a]] -> [[a]]
sortList x = sortBy myCompare x
-- Die Indexfunktion --
getIndex :: [[a]] -> Int -> Int
getIndex [] y = 0
getIndex (x:xs) y
| length x <= y = 1 + getIndex xs y
| otherwise = 0
where (x:xs) = sortList (x:xs)
main = do
print (sortList [[4],[3,5,3],[4,3],[3,5,5,6,1],[]])
print (getIndex [[4],[3,5,3],[4,3],[3,5,5,6,1],[]] 2)
Getting it to terminate
The problem is in this case
getIndex (x:xs) y
| length x <= y = 1 + getIndex xs y
| otherwise = 0
where (x:xs) = sortList (x:xs)
You're confusing which (x:xs) is which. You should instead do
getIndex zs y
| length x <= y = 1 + getIndex xs y
| otherwise = 0
where (x:xs) = sortList zs
giving
Main> main
[[],[4],[4,3],[3,5,3],[3,5,5,6,1]]
3
*Main> getIndex [[],[2],[4,5]] 1
2
*Main> getIndex [[],[2],[4,5]] 5
3
This gives you the number of the first list of length at least y in the sorted list, which actually answers the question "How many lists are of length at most y in the original?"
How can we find out other facts?
If you want position from the original list, you can tag the entries with their position, using zip:
*Main> zip [1..] [[4],[3,5,3],[4,3],[3,5,5,6,1],[]]
[(1,[4]),(2,[3,5,3]),(3,[4,3]),(4,[3,5,5,6,1]),(5,[])]
Let's make a utility function for working with those:
hasLength likeThis (_,xs) = likeThis (length xs)
We can use it like this:
*Main> hasLength (==4) (1,[1,2,3,4])
True
*Main> filter (hasLength (>=2)) (zip [1..] ["","yo","hi there","?"])
[(2,"yo"),(3,"hi there")]
Which means it's now easy to write a function that gives you the index of the first list of length longer than y:
whichIsLongerThan xss y =
case filter (hasLength (>y)) (zip [1..] xss) of
[] -> error "nothing long enough" -- change this to 0 or (length xss + 1) if you prefer
(x:xs) -> fst x
This gives us
*Main> whichIsLongerThan [[4],[3,5,3],[4,3],[3,5,5,6,1],[]] 2
2
*Main> whichIsLongerThan [[4],[3,5,3],[4,3],[3,5,5,6,1],[]] 3
4
*Main> whichIsLongerThan [[4],[3,5,3],[4,3],[3,5,5,6,1],[]] 0
1
Shorter?
but we can do similar tricks:
whichIsShorterThan xss y =
case filter (hasLength (<y)) (zip [1..] xss) of
[] -> error "nothing short enough" -- change this to 0 or (length xss + 1) if you prefer
(x:xs) -> fst x
so you get
*Main> whichIsShorterThan [[4],[3,5,3],[4,3],[3,5,5,6,1],[]] 2
1
*Main> whichIsShorterThan [[4],[3,5,3],[4,3],[3,5,5,6,1],[]] 1
5
*Main> whichIsShorterThan [[4],[3,5,3],[4,3],[3,5,5,6,1],[]] 0
*** Exception: nothing short enough
Generalised
Let's pull out the common theme there:
whichLength :: (Int -> Bool) -> [[a]] -> Int
whichLength likeThis xss =
case filter (hasLength likeThis) (zip [1..] xss) of
[] -> error "nothing found" -- change this to 0 or (length xss + 1) if you prefer
(x:xs) -> fst x
so we can do
*Main> whichLength (==5) [[4],[3,5,3],[4,3],[3,5,5,6,1],[]]
4
*Main> whichLength (>2) [[4],[3,5,3],[4,3],[3,5,5,6,1],[]]
2
Do you mean index of the firs sublist with length > y? If that's not the goal (and < y is), then
length x <= y = 1 + getIndex xs y
should be
length x >= y = 1 + getIndex xs y
Also, (x:xs) = sortList (x:xs) is bottom, since it will never end. If you want to sort it somehow, you might follow AndrewC's solution.
let (and where) bindings in Haskell are recursive: LHS and RHS both belong (and thus refer to) to the same new scope. Your code is equivalent to
........
getIndex (x:xs) y =
let -- new, extended scope, containing definitions for
(x:xs) = a -- new variables x, xs, a ... the original vars x, xs
a = sortList a -- are inaccessible, __shadowed__ by new definitions
in -- evaluated inside the new, extended scope
if length x <= y -- x refers to the new definition
then 1 + getIndex xs y
else 0
When the value of x is demanded by length, its new definition (x:xs) = a demands the value of a, which is directly defined in terms of itself, a = sortList a:
a = sortList a
= sortList (sortList a)
= sortList (sortList (sortList a))
= sortList (sortList (sortList (sortList a)))
= ....
A black hole.
I'm trying to make a function that takes in a list, and if one of the elements is negative, then any elements in that list that are equal to its positive counterpart should be changed to 0. Eg, if there is a -2 in a list, then all 2's in that list should be changed to 0.
Any ideas why it only works for some cases and not others? I'm not understanding why this is, I've looked it over several times.
changeToZero [] = []
changeToZero [x] = [x]
changeToZero (x:zs:y:ws) | (x < 0) && ((-1)*(x) == y) = x : zs : 0 : changeToZero ws
changeToZero (x:xs) = x : changeToZero xs
changeToZero [-1,1,-2,2,-3,3]
-- [-1,1,-2,2,-3,3]
changeToZero [-2,1,2,3]
-- [-2,1,0,3]
changeToZero [-2,1,2,3,2]
-- [-2,1,0,3,2]
changeToZero [1,-2,2,2,1]
-- [1,-2,2,0,1]
I think a list comprehension is both clearer and easier to get right here.
changeToZero xs = [if x > 0 && (-x) `elem` xs then 0 else x | x <- xs]
If you need something more efficient, you can build a set of the negative elements and check that instead of using elem.
import qualified Data.Set as Set
changeToZero' xs = [if (-x) `Set.member` unwanted then 0 else x | x <- xs]
where unwanted = Set.fromList $ filter (< 0) xs
you don't anctually remember which negative symbols you found in the list
import qualified Data.Set as S
changeToZero :: [Int] -> [Int]
changeToZero [] = []
changeToZero xs = reverse . snd $ foldl f (S.empty,[]) xs
where
f (negs,res) x | x < 0 = (S.insert (-x) negs, x:res)
| S.member x negs = (negs,0:res)
| otherwise = (negs,x:res)
Well, building on the answer from #jdevelop, if the negative has to appear before the positive in order to count, then you can build the result with a single pass over the input, without the need to reverse it:
import qualified Data.Set as S
import Control.Monad.State
changeToZero :: [Int] -> [Int]
changeToZero xs = evalState (mapM f xs) S.empty where
f x | x < 0 = modify (S.insert (-x)) >> return x
| otherwise = gets (S.member x) >>= \hasNeg -> return $ if hasNeg then 0 else x
In this way, you can get an answer to
take 4 $ changeToZero $ 1 : (-2) : 3 : 2 : undefined
where the other solutions will fail.
** Edit **
Here is the same thing, but without the State monad, which makes it easier to understand:
changeToZero' :: [Int] -> [Int]
changeToZero' = go S.empty where
go _ [] = []
go s (x:xs) | x < 0 = x : go (S.insert (-x) s) xs
| S.member x s = 0 : go s xs
| otherwise = x : go s xs