Parameterizing the binary operation when combining two lists - haskell

I'm trying to write a program that takes in two lists and a binary operation and takes each element of one list and applies it to the other using the binary operation. I have it working but not sure how to change it so it works with any binary operator. Here's examples :
myFunction (+) [100,200,300] [4,3,2,1] would return
[96,97,98,99,196,197,198,199,296,297,298,299]
myFunction (+) [100,200,300] [4,3,2,1] would return
[96,97,98,99,196,197,198,199,296,297,298,299]
This is what I have working with specific binary operations
oneEle :: Char -> Integer -> [Integer] -> [Integer]
oneEle a x [] = []
oneEle a x y
| (a == '+') = [p + x | p <- y]
| (a == '-') = [p - x | p <- y]
| (a == '*') = [p * x | p <- y]
| (a == ':') = [p * x | p <- y]
myFunction :: Char -> [Integer] -> [Integer] -> [Integer]
myFunction a [] [] = []
myFunction a [] y = []
myFunction a x [] = []
myFunction a (x:xs) (y:ys) = oneEle a x ([y] ++ ys) ++ myFunction a xs ([y]++ys)

The simplest way is a list comprehension:
myFunction f xs ys = [f x y | x <- xs, y <- ys]
It may not even be worth defining a new function; instead, just inline that content to the call site.
This function is also available from the standard library by the names liftM2 and liftA2.

Related

Use Int to return specific tuples in list causes overflow

The code should take an Int and compare it to the first Int in listed tuple (the other Ints don't matter) so Int x should compare to the p in ((p,q,r) : ys) and return a list [(p,q,r),(p,q,r)] so long as x == p. The code compiles but it overflows when tested and I'm not sure if it's a syntax issue or if I'm not compensating for the full list.
listTuples :: Int -> [(Int, Int, Int)] -> [(Int,Int,Int)]
listTuples x [] = []
listTuples x ((p,q,r) : ys)
| x == p = listTuples x ((p,q,r) : ys)
| otherwise = []
The test:
listTuples 3 [(3,4,5),(4,3,5),(3,6,7)]
Return:
[(3,4,5),(3,6,7)]
This is not “overflow”, it's infinite recursion. note that
listTuples x ((p,q,r) : ys)
= listTuples x ((p,q,r) : ys)
= listTuples x ((p,q,r) : ys)
= ...
I reckon what you want it this:
listTuples x ((p,q,r) : ys)
| x == p = (p,q,r) : listTuples x ys
| otherwise = listTuples x ys
As Daniel Wagner commented, a better way of writing this function is
filter (\(p,_,_) -> x==p)
You can do it using filter
listTuples' :: Int -> [(Int, Int, Int)] -> [(Int, Int, Int)]
listTuples' x ls = filter (\(p, _, _) -> p == x) ls

Haskell - output a type which takes 2 parametes

I'm trying to make an array of my own type letterCount in form of [('letter',occurance),(),...]. How can I make an output of a type which takes 2 parameters. Here's my code:
type LetterCount = (Char,Int)
letterOccur :: Char->[Char] -> Int
letterOccur c [] = 0
letterOccur c (x:xs) = if (c == x) then ((letterOccur c xs) + 1)
else letterOccur c xs
letterStats :: [Char] -> [LetterCount]
letterStats :: [] = []
letterStats (x:xs) = [x,(letterOccur x (x:xs))] ++ letterStats xs
I'm guessing you're trying to do something like this:
letterStats :: [Char] -> [LetterCount]
letterStats :: [] = []
letterStats (x:xs) = (x, (+1) $ letterOccur x xs) : letterStats xs
All you want to do is add +1 as you are not counting x when checking xs for all x occurances. Also what you want is to return a list of the letterCount type which is a Tuple not a list, therefore I changed
[x, letterOccur x xs] ++ letterStats xs
to
(x, (+1) $ letterOccur x xs) : letterStats xs
Although you could also do this:
[(x, (+1) $ letterOccur x xs)] ++ letterStats xs
But is unnecessary.

How can i make Insert_sort high-order-function in Haskell

plz watch my code
insert x [] = [x]
insert x (y:ys)
| x < y = x:y:ys
| x == y = y:ys ++ [x]
| otherwise = y:insert x ys
insert_sort [] = []
insert_sort (x:xs) = insert x (insert_sort xs)
insert_pair (x,y) [] = [(x,y)]
insert_pair (x,y) ((a,b):yd)
| x > a = (a,b):insert_pair (x,y) yd
| otherwise = (x,y):(a,b):yd
insert_sort_pair [] = []
insert_sort_pair (x:xs) = insert_pair x (insert_sort_pair xs)
insert_high f [] = []
insert_high f (x:y:ys)
| f x y = x:y:ys
| otherwise = y:insert x ys
insert_high f ((a,b):(c,d):yd)
| f a c = (a,b):insert_pair (c,d) yd
| otherwise = (a,b):(c,d):yd
insert_sort_high f [] = []
insert_sort_high f (x:xs) = insert_high (f) x (insert_sort_high (f) xs)
I want to make insert_sort-high can do both insert_sort and insert_pair_sort.
"insert_sort_pair" compare the number in (number,symbol).
For example:
insert_sort_high (<) [3,5,2,1,4] -> [1,2,3,4,5]
insert_sort_high (>) [(2,'a'),(3,'b'),(1,'c')] -> [(1,'c'),(2,'a'),(3,'b')]
But, it doesn't work... how can i fix it?
First, a fundamental misunderstanding.
Write a type for insert_high - it should probably be (a -> a -> Bool) -> [a] -> [a]. But you've written a specialization for lists of tuples, so you've forced it to be less general than that.
You can only cover the general case. You're being misled by your examples.
I'd argue what you really want is
λ insert_sort_high (<) [3,5,2,1,4]
[1,2,3,4,5]
λ insert_sort_high (\(x,y) (a,b) -> x < a) [(2,'a'), (3,'b'), (1,'c')]
[(1,'c'),(2,'a'),(3,'b')]
The latter can be written a little more easily as
λ :m +Data.Function
λ insert_sort_high ((<) `on` fst) [(2,'a'), (3,'b'), (1,'c')]
[(1,'c'),(2,'a'),(3,'b')]
Of course, that's only if you only want sorting to be on the first element of the pair.
λ insert_sort_high ((<) `on` fst) [(2,'a'), (3,'b'), (1, 'a'), (1,'b'), (1,'c'), (1,'a')]
[(1,'a'),(1,'c'),(1,'b'),(1,'a'),(2,'a'),(3,'b')]
If you want to sort by the entire pair, you can do that too
λ (1,'a') < (1,'b')
True
λ (1,'z') < (2,'a')
True
λ insert_sort_high (<) [(2,'a'), (3,'b'), (1,'a'),(1,'b'),(1,'c'), (1,'a')]
[(1,'a'),(1,'a'),(1,'b'),(1,'c'),(2,'a'),(3,'b')]
But I digress.
With that in mind all you really need to do is delete your tuple case, and clean up some typos.
insert_high :: (a -> a -> Bool) -> a -> [a] -> [a]
insert_high _ x [] = [x]
insert_high f x (y:ys)
| f x y = x:y:ys
| otherwise = y : insert_high f x ys
insert_sort_high _ [] = []
insert_sort_high f (x:xs) = insert_high f x (insert_sort_high f xs)

Haskell- parse error on input

I have the following code which
halves each even number in a list:
halfEvens :: [Int] -> [Int]
halfEvens [xs]
| x `mod` 2 == 0 = x `div` 2
| otherwise = x
where x <- xs
And I get the following error:
parse error on input '<-'
I was careful so I respected the indentations...any other ideas what I'm doing wrong?
There are two main issues in your code:
where block defines functions, so, you should use = instead of <-
Your function accepts lists with exactly one element inside
Instead of it I suggest you write separate function halfIfEven:
Prelude> let halfIfEven x = if even x then x `div` 2 else x
Then define halfEvens using map:
Prelude> let halfEvens = map halfIfEven
Prelude> halfEvens [1..10]
[1,1,3,2,5,3,7,4,9,5]
But, of course, you could write this using pattern matching, although it is less readable:
halfIfEven :: Int -> Int
halfIfEven x | even x = x `div` 2
| otherwise = x
halfEvens :: [Int] -> [Int]
halfEvens [] = []
halfEvens (x:xs) = (halfIfEven x):(halfEvens xs)

Haskell filter string with only the first occuring Char

I want to filter a string with a string.
What I want is to use delete every first occurring char.
myFunc :: String -> String -> String
Like:
myFunc "dddog" "bigdddddog" = "biddg"
In "dddog": 3x d, 1x o, 1x g
In the second string it removed 3x d, 1x o and 1x g
So the output: biddg
I can't use filter for it, because it will delete all occurring chars.
And I struggled a long time with it.
Thanks in advance:)
How about
Prelude> :m +Data.List
Prelude Data.List> "bigdddddog" \\ "dddog"
"biddg"
Not the nicest solution, but you can understand easier what's going on:
myfunc :: String -> String -> String
myfunc [] xs = xs
myfunc (x:xs) ys = myfunc xs $ remove x ys
where
remove _ [] = []
remove x (y:ys) = if x == y then ys else y : remove x ys
As you commented, you want to use guards. Do you mean this?
myfunc :: String -> String -> String
myfunc [] xs = xs
myfunc (x:xs) ys = myfunc xs $ remove x ys
remove :: Char -> String -> String
remove _ [] = []
remove x (y:ys)
| x == y = ys
| otherwise = y : remove x ys
some of the other solutions don't seem to produce the same result you posted. I think I have a simple solution that does what you asked for but I may be misunderstanding what you want. All I do in the following code is go though the list and apply 'delete' to every element in the list. It's not exactly efficient but it gets the job done.
import Data.List
myFunc (x:xs) ys = myFunc xs (delete x ys)
myFunc [] ys = ys
There are perhaps more efficient solutions like storing the "to remove" list in a tree with the number of occurences stored as the value then traversing the main list testing to see if the count at that key was still greater than zero. I think that would give you O(n*lg(m)) (where n is the size of the list to be removed from and m is the size of the "to remove" list) rather than O(n*m) as is the case above. This version could also be maid to be lazy I think.
edit:
Here is the tree version I was talking abut using Data.Map. It's a bit complex but should be more efficient for large lists and it is somewhat lazy
myFunc l ys = myFunc' (makeCount l) ys
where makeCount xs = foldr increment (Map.fromList []) xs
increment x a = Map.insertWith (+) x 1 a
decrement x a = Map.insertWith (flip (-)) x 1 a
getCount x a = case Map.lookup x a of
Just c -> c
Nothing -> 0
myFunc' counts (x:xs) = if (getCount x counts) > 0
then myFunc' (decrement x counts) xs
else x : myFunc' counts xs
myFunc' _ [] = []
I am not quite sure about how you want your function to behave, how about this?
import Data.List (isPrefixOf)
myFunc :: String -> String -> String
myFunc _ [] = []
myFunc y x'#(x:xs) | y `isPrefixOf` x' = drop (length y) x'
| otherwise = x : myFilter xs y
This gives the following output in GHCi:
> myFunc "dddog" "bigdddddog"
> "bigdd"
If this is not what you had in mind, please give another input/output example.
I like kaan's elegant solution. In case you meant this...here's one where the "ddd" would only be removed if matched as a whole:
import Data.List (group,isPrefixOf,delete)
f needles str = g (group needles) str where
g needles [] = []
g needles xxs#(x:xs)
| null needle' = [x] ++ g needles xs
| otherwise = let needle = head needle'
in g (delete needle needles) (drop (length needle) xxs)
where needle' = dropWhile (not . flip isPrefixOf xxs) needles
Output:
*Main> f "dddog" "bigdddddog"
"biddg"
*Main> f "dddog" "bdigdogd"
"bdidgd"
No monadic solution yet, there you go:
import Control.Monad.State
myFunc :: String -> State String String
myFunc [] = return ""
myFunc (x:xs) = get >>= f where
f [] = return (x:xs)
f (y:ys) = if y == x then put ys >> myFunc xs
else myFunc xs >>= return . (x:)
main = do
let (a,b) = runState (myFunc "bigdddddog") "dddog" in
putStr a
Using predefined functions from Data.List,
-- mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
-- lookup :: (Eq a) => a -> [(a, b)] -> Maybe b
{-# LANGUAGE PatternGuards #-}
import Data.List
picks [] = [] -- http://stackoverflow.com/a/9889702/849891
picks (x:xs) = (x,xs) : [ (y,x:ys) | (y,ys) <- picks xs]
myFunc a b = concat . snd $ mapAccumL f (picks a) b
where
f acc x | Just r <- lookup x acc = (picks r,[])
f acc x = (acc,[x])
Testing:
Prelude Data.List> myFunc "dddog" "bigdddddog"
"biddg"
edit: this is of course a bit more complex than (\\). I'll let it stand as an illustration. There could be some merit to it still, as it doesn't copy the 2nd (longer?) string over and over, for each non-matching character from the 1st (shorter) string, as delete apparently does, used in (\\) = foldl (flip delete).

Resources