Haskell numeric list processing - haskell

I am having trouble finishing this problem. Any hints to a possible solution will be appreciated.
Given a Double value v and a list of Double values xs, calcList returns a list of Doubles
according to the following rules:
For each value x in xs, if x is not positive, there will be no corresponding value in the output list.
Otherwise, the corresponding output value will be x * ln x.
However, this value will be in the output list if and only if its value is greater than v.
The order of the corresponding output values (if present) should be the same as the input
values.
The followings are some examples:
calcList 1.0 [] = []
calcList 1.0 [3.0] = [3.2958]
calcList 1.0 [-1.0, 1.0, 3.0, 5.0, 7.0, 9.0] = [3.2958, 8.0472, 13.6214, 19.7750]
calcList 100.0 [1.0 .. 40.0] = [102.0359, 106.4536, 110.9035, 115.3847, 119.8963, 124.4372, 129.0067, 133.6040, 138.2283, 142.8789, 147.5552]
This what I have so far:
positive :: Double -> Bool
positive x = x > 0.0
calcValue :: Double -> Double
calcValue x = log x * x
calcList :: Double -> [Double] -> [Double]
calcList v xs = []
calcList v xs

So it looks like there are 3 steps.
Get rid of elements <= 0 (filter)
Multiply each remaining elements by its natural log (map)
Get rid of elements <= v (filter)
Instead of applying these each to an input, we can compose the functions using (.) (sincef.g == \x -> f (g x)).
calcList = \v -> filter (>v) . map (\x -> x*log x) . filter (>0)
You should checkout the docs on filter and map. Also this chapter from Learn You A Haskell would be a good read.

We can use an approach where we use functions like filter, and map. An equivalent solution can be obtained with list comprehension:
calcList :: (Ord d, Floating d) => d -> [d] -> [d]
calcList v xs = [xlogx | x <- xs, x > 0, let xlogx = x * log x, xlogx > v]
We thus here use x <- xs to iterate over the elements in xs, by using x > 0 we filter values such that only values where x > 0 are considered. Next we define a variable xlogx as let xlogx = x * log x, and then we have an extra filter that checks if xlogx > v.
The yield part of the list comprehension (the part before the pipe char |) specifies that we add xlogx to the list.

Another approach could be
calcList :: Double -> [Double] -> [Double]
calcList v [] = []
calcList v (x:xs) = case (positive x) of {
False -> calcList v xs;
True -> case ((calcValue x) > v) of {
False -> calcList v xs;
True -> (calcValue x):(calcList v xs);
};
}
In each of the cases you check for one of the conditions, plus you add the numbers at the beginning of the list so the order will be the same.

Related

Counting the occurrences of chararacters in a string

I got the task to count the number of occurrences of each (lower case) character in a string. I am not allowed to use any function of the library, I came up with the following, working solution.
occur :: String -> [(Char,Int)]
occur y = [ (x,count x y) | x<-['a'..'z'], count x y > 0]
I was trying at first:
occur2 :: String -> [(Char,Int)]
occur2 y = [ (x,z) | x<-['a'..'z'], z<- count x y, count x y > 0]
I defined the helper function count like this:
count :: Char -> String -> Int
count k str = length [n | n <- str, n == k]
Two questions:
Why is occur2 not working?
Is there any way to define occur without my aux function count?
occur2 isn't working because count x y is not a list, so it can't be used for a generator expression like in z <- count x y. Instead, use a let expression.
You can remove the count definition by inlining it.
occur :: String -> [(Char,Int)]
occur y = [ (x,z) | x <- ['a'..'z'], let z = length [n | n <- y, n == x], z > 0]
If you were to use libraries, a simple and efficient implementation would be to use a MultiSet.
import qualified Data.MultiSet as MS
occur :: String -> [(Char,Int)]
occur = MS.toAscOccurList . MS.fromList . filter (\c -> c >= 'a' && c <= 'z')

Recursively dropping elements from list in Haskell

Right now I'm working on a problem in Haskell in which I'm trying to check a list for a particular pair of values and return True/False depending on whether they are present in said list. The question goes as follows:
Define a function called after which takes a list of integers and two integers as parameters. after numbers num1 num2 should return true if num1 occurs in the list and num2 occurs after num1. If not it must return false.
My plan is to check the head of the list for num1 and drop it, then recursively go through until I 'hit' it. Then, I'll take the head of the tail and check that against num2 until I hit or reach the end of the list.
I've gotten stuck pretty early, as this is what I have so far:
after :: [Int] -> Int -> Int -> Bool
after x y z
| y /= head x = after (drop 1 x) y z
However when I try to run something such as after [1,4,2,6,5] 4 5 I get a format error. I'm really not sure how to properly word the line such that haskell will understand what I'm telling it to do.
Any help is greatly appreciated! Thanks :)
Edit 1: This is the error in question:
Program error: pattern match failure: after [3,Num_fromInt instNum_v30 4] 3 (Num_fromInt instNum_v30 2)
Try something like this:
after :: [Int] -> Int -> Int -> Bool
after (n:ns) a b | n == a = ns `elem` b
| otherwise = after ns a b
after _ _ _ = False
Basically, the function steps through the list, element by element. If at any point it encounters a (the first number), then it checks to see if b is in the remainder of the list. If it is, it returns True, otherwise it returns False. Also, if it hits the end of the list without ever seeing a, it returns False.
after :: Eq a => [a] -> a -> a -> Bool
after ns a b =
case dropWhile (/= a) ns of
[] -> False
_:xs -> b `elem` xs
http://hackage.haskell.org/package/base-4.8.2.0/docs/src/GHC.List.html#dropWhile
after xs p1 p2 = [p1, p2] `isSubsequenceOf` xs
So how can we define that? Fill in the blanks below!
isSubsequenceOf :: Eq a => [a] -> [a] -> Bool
[] `isSubsequenceOf` _ = ?
(_ : _) `isSubsequenceOf` [] = ?
xss#(x : xs) `isSubsequenceOf` (y:ys)
| x == y = ?
| otherwise = ?
after :: [Int] -> Int -> Int -> Bool
Prelude> let after xs a b = elem b . tail $ dropWhile (/=a) xs
Examples:
Prelude> after [1,2,3,4,3] 88 7
*** Exception: Prelude.tail: empty list
It raises an exception because of tail. It's easy to write tail' such that it won't raise that exception. Otherwise it works pretty well.
Prelude> after [1,2,3,4,3] 2 7
False
Prelude> after [1,2,3,4,3] 2 4
True

Generate next lexicographical string in Haskell

If I was given a string like skhfbvqa, how would I generate the next string? For this example, it would be skhfbvqb, and the next string of that would be skhfbvqc, and so on. The given string (and the answer) will always be N characters long (in this case, N=8).
What I tried:
I tried to generate the entire (infinite) list of possible combinations, and get the required (next) string of the given string, but unsurprisingly, it's so slow, that I don't even get the answer for N=6.
I used list comprehension:
allStrings = [ c : s | s <- "" : allStrings, c <- ['a'..'z'] ]
main = do
input <- readFile "k.in"
putStrLn . head . tail . dropWhile (not . (==) input) . map reverse $ allStrings
(Please excuse my incredibly bad Haskell-ing :) Still a noob)
So my question is, how can I do this? If there are multiple methods, a comparison between them is much appreciated. Thanks!
Here's a version with base conversion (this way you could add and subtract arbitrarily if you like):
encode x base = encode' x [] where
encode' x' z | x' == 0 = z
| otherwise = encode' (div x' base) ((mod x' base):z)
decode num base =
fst $ foldr (\a (b,i) -> (b + a * base^i,i + 1)) (0,0) num
Output:
*Main> map (\x -> toEnum (x + 97)::Char)
$ encode (decode (map (\x -> fromEnum x - 97) "skhfbvqa") 26 + 1) 26
"skhfbvqb"
I would go and make a helper function f :: Integer -> String and one g :: String -> Integer, where f 1 = "a", ... f 27 = "aa", f 28 = "ab" and so on and the inverse g.
Then incrementString = f . succ . g
Note: I omitted the implementation of f on purpose for learning
Update
for a different approach you could define a increment with carry function inc' :: Char -> (Char, Bool), and then
incString :: String -> String
incString = reverse . incString'
where incString' [] = []
incString' (x:xs) = case inc' x of (x',True) -> x': incString' xs
(x',False) -> x':xs
Note: this function is not tail recursive!
I found this to work. It just uses pattern matching to see if the string begins with a z and adds an additional a accordingly.
incrementString' :: String -> String
incrementString' [] = ['a']
incrementString' ('z':xs) = 'a' : incrementString' xs
incrementString' (x:xs) = succ x : xs
incrementString :: String -> String
incrementString = reverse . incrementString' . reverse

Defining a Boolean function on Haskell that determines if an element occurs once in a list

So I'm trying to define a function in Haskell that if given an integer and a list of integers will give a 'true' or 'false' whether the integer occurs only once or not.
So far I've got:
let once :: Eq a => a -> [a] -> Bool; once x l =
But I haven't finished writing the code yet. I'm very new to Haskell as you may be able to tell.
Start off by using pattern matching:
once x [] =
once x (y:ys) =
This won't give you a good program immediately, but it will lead you in the right direction.
Here's a solution that doesn't use pattern matching explicitly. Instead, it keeps track of a Bool which represents if a occurance has already been found.
As others have pointed out, this is probably a homework problem, so I've intentionally left the then and else branches blank. I encourage user3482534 to experiment with this code and fill them in themselves.
once :: Eq a => a -> [a] -> Bool
once a = foldr f False
where f x b = if x == a then ??? else ???
Edit: The naive implementation I was originally thinking of was:
once :: Eq a => a -> [a] -> Bool
once a = foldr f False
where f x b = if x == a then b /= True else b
but this is incorrect as,
λ. once 'x' "xxx"
True
which should, of course, be False as 'x' occurs more than exactly once.
However, to show that it is possible to write once using a fold, here's a revised version that uses a custom monoid to keep track of how many times the element has occured:
import Data.List
import Data.Foldable
import Data.Monoid
data Occur = Zero | Once | Many
deriving Eq
instance Monoid Occur where
mempty = Zero
Zero `mappend` x = x
x `mappend` Zero = x
_ `mappend` _ = Many
once :: Eq a => a -> [a] -> Bool
once a = (==) Once . foldMap f
where f x = if x == a then Once else Zero
main = do
let xss = inits "xxxxx"
print $ map (once 'x') xss
which prints
[False,True,False,False,False]
as expected.
The structure of once is similar, but not identical, to the original.
I'll answer this as if it were a homework question since it looks like one.
Read about pattern matching in function declarations, especially when they give an example of processing a list. You'll use tools from Data.List later, but probably your professor is teaching about pattern matching.
Think about a function that maps values to a 1 or 0 depending on whethere there is a match ...
match :: a -> [a] -> [Int]
match x xs = map -- fill in the thing here such that
-- match 3 [1,2,3,4,5] == [0,0,1,0,0]
Note that there is the sum function that takes a list of numbers and returns the sum of the numbers in the list. So to count the matches a function can take the match function and return the counts.
countN :: a -> [a] -> Int
countN x xs = ? $ match x xs
And finally a function that exploits the countN function to check for a count of only 1. (==1).
Hope you can figure out the rest ...
You can filter the list and then check the length of the resulting list. If length == 1, you have only one occurrence of the given Integer:
once :: Eq a => a -> [a] -> Bool
once x = (== 1) . length . filter (== x)
For counting generally, with import Data.List (foldl'), pointfree
count pred = foldl' (\ n x -> if pred x then n + 1 else n) 0
applicable like
count (< 10) [1 .. 10] == 9
count (== 'l') "Hello" == 2
gives
once pred xs = count pred xs == 1
Efficient O(n) short-circuit predicated form, testing whether the predicate is satisfied exactly once:
once :: (a -> Bool) -> [a] -> Bool
once pred list = one list 0
where
one [] 1 = True
one [] _ = False
one _ 2 = False
one (x : xs) n | pred x = one xs (n + 1)
| otherwise = one xs n
Or, using any:
none pred = not . any pred
once :: (a -> Bool) -> [a] -> Bool
once _ [] = False
once pred (x : xs) | pred x = none pred xs
| otherwise = one pred xs
gives
elemOnce y = once (== y)
which
elemOnce 47 [1,1,2] == False
elemOnce 2 [1,1,2] == True
elemOnce 81 [81,81,2] == False

Doing a binary search on some elements in Haskell

I'm trying to complete the last part of my Haskell homework and I'm stuck, my code so far:
data Entry = Entry (String, String)
class Lexico a where
(<!), (=!), (>!) :: a -> a -> Bool
instance Lexico Entry where
Entry (a,_) <! Entry (b,_) = a < b
Entry (a,_) =! Entry (b,_) = a == b
Entry (a,_) >! Entry (b,_) = a > b
entries :: [(String, String)]
entries = [("saves", "en vaut"), ("time", "temps"), ("in", "<`a>"),
("{", "{"), ("A", "Un"), ("}", "}"), ("stitch", "point"),
("nine.", "cent."), ("Zazie", "Zazie")]
build :: (String, String) -> Entry
build (a, b) = Entry (a, b)
diction :: [Entry]
diction = quiksrt (map build entries)
size :: [a] -> Integer
size [] = 0
size (x:xs) = 1+ size xs
quiksrt :: Lexico a => [a] -> [a]
quiksrt [] = []
quiksrt (x:xs)
|(size [y|y <- xs, y =! x]) > 0 = error "Duplicates not allowed."
|otherwise = quiksrt [y|y <- xs, y <! x]++ [x] ++ quiksrt [y|y <- xs, y >! x]
english :: String
english = "A stitch in time save nine."
show :: Entry -> String
show (Entry (a, b)) = "(" ++ Prelude.show a ++ ", " ++ Prelude.show b ++ ")"
showAll :: [Entry] -> String
showAll [] = []
showAll (x:xs) = Main.show x ++ "\n" ++ showAll xs
main :: IO ()
main = do putStr (showAll ( diction ))
The question asks:
Write a Haskell programs that takes
the English sentence 'english', looks
up each word in the English-French
dictionary using binary search,
performs word-for-word substitution,
assembles the French translation, and
prints it out.
The function 'quicksort' rejects
duplicate entries (with 'error'/abort)
so that there is precisely one French
definition for any English word. Test
'quicksort' with both the original
'raw_data' and after having added
'("saves", "sauve")' to 'raw_data'.
Here is a von Neumann late-stopping
version of binary search. Make a
literal transliteration into Haskell.
Immediately upon entry, the Haskell
version must verify the recursive
"loop invariant", terminating with
'error'/abort if it fails to hold. It
also terminates in the same fashion if
the English word is not found.
function binsearch (x : integer) : integer
local j, k, h : integer
j,k := 1,n
do j+1 <> k --->
h := (j+k) div 2
{a[j] <= x < a[k]} // loop invariant
if x < a[h] ---> k := h
| x >= a[h] ---> j := h
fi
od
{a[j] <= x < a[j+1]} // termination assertion
found := x = a[j]
if found ---> return j
| not found ---> return 0
fi
In the Haskell version
binsearch :: String -> Integer -> Integer -> Entry
as the constant dictionary 'a' of type
'[Entry]' is globally visible. Hint:
Make your string (English word) into
an 'Entry' immediately upon entering
'binsearch'.
The programming value of the
high-level data type 'Entry' is that,
if you can design these two functions
over the integers, it is trivial to
lift them to to operate over Entry's.
Anybody know how I'm supposed to go about my binarysearch function?
The instructor asks for a "literal transliteration", so use the same variable names, in the same order. But note some differences:
the given version takes only 1
parameter, the signature he gives
requires 3. Hmmm,
the given version is not recursive, but he asks for a
recursive version.
Another answer says to convert to an Array, but for such a small exercise (this is homework after all), I felt we could pretend that lists are direct access. I just took your diction::[Entry] and indexed into that. I did have to convert between Int and Integer in a few places.
Minor nit: You've got a typo in your english value (bs is a shortcut to binSearch I made):
*Main> map bs (words english)
[Entry ("A","Un"),Entry ("stitch","point"),Entry ("in","<`a>"),Entry ("time","te
mps"),*** Exception: Not found
*Main> map bs (words englishFixed)
[Entry ("A","Un"),Entry ("stitch","point"),Entry ("in","<`a>"),Entry ("time","te
mps"),Entry ("saves","en vaut"),Entry ("nine.","cent.")]
*Main>
A binary search needs random access, which is not possible on a list. So, the first thing to do would probably be to convert the list to an Array (with listArray), and do the search on it.
here's my code for just the English part of the question (I tested it and it works perfectly) :
module Main where
class Lex a where
(<!), (=!), (>!) :: a -> a -> Bool
data Entry = Entry String String
instance Lex Entry where
(Entry a _) <! (Entry b _) = a < b
(Entry a _) =! (Entry b _) = a == b
(Entry a _) >! (Entry b _) = a > b
-- at this point, three binary (infix) operators on values of type 'Entry'
-- have been defined
type Raw = (String, String)
raw_data :: [Raw]
raw_data = [("than a", "qu'un"), ("saves", "en vaut"), ("time", "temps"),
("in", "<`a>"), ("worse", "pire"), ("{", "{"), ("A", "Un"),
("}", "}"), ("stitch", "point"), ("crime;", "crime,"),
("a", "une"), ("nine.", "cent."), ("It's", "C'est"),
("Zazie", "Zazie"), ("cat", "chat"), ("it's", "c'est"),
("raisin", "raisin sec"), ("mistake.", "faute."),
("blueberry", "myrtille"), ("luck", "chance"),
("bad", "mauvais")]
cook :: Raw -> Entry
cook (x, y) = Entry x y
a :: [Entry]
a = map cook raw_data
quicksort :: Lex a => [a] -> [a]
quicksort [] = []
quicksort (x:xs) = quicksort (filter (<! x) xs) ++ [x] ++ quicksort (filter (=! x) xs) ++ quicksort (filter (>! x) xs)
getfirst :: Entry -> String
getfirst (Entry x y) = x
getsecond :: Entry -> String
getsecond (Entry x y) = y
binarysearch :: String -> [Entry] -> Int -> Int -> String
binarysearch s e low high
| low > high = " NOT fOUND "
| getfirst ((e)!!(mid)) > s = binarysearch s (e) low (mid-1)
| getfirst ((e)!!(mid)) < s = binarysearch s (e) (mid+1) high
| otherwise = getsecond ((e)!!(mid))
where mid = (div (low+high) 2)
translator :: [String] -> [Entry] -> [String]
translator [] y = []
translator (x:xs) y = (binarysearch x y 0 ((length y)-1):translator xs y)
english :: String
english = "A stitch in time saves nine."
compute :: String -> [Entry] -> String
compute x y = unwords(translator (words (x)) y)
main = do
putStr (compute english (quicksort a))
An important Prelude operator is:
(!!) :: [a] -> Integer -> a
-- xs!!n returns the nth element of xs, starting at the left and
-- counting from 0.
Thus, [14,7,3]!!1 ~~> 7.

Resources