I want to compute values in an infinite grid of integers, where each square contains an integer from 0 to 3. I designed a function that increments a square: it adds one to the value of that square, but if the square would then hold a 4, it sets the square to 0 and calls itself on the four adjacent squares.
type Board = (Int,Int) -> Int
setSquareTo :: Int -> (Int,Int) -> Board -> Board
setSquareTo n (x,y) b (z,w) | x == z && y == w = n
| otherwise = b (z,w)
incSquare :: (Int,Int) -> Board -> Board
incSquare (x,y) b | b (x,y) == 3 = incSquare (x+1,y).incSquare (x,y+1).incSquare (x-1,y).incSquare (x,y-1).setSquareTo 0 (x,y) $ b
| otherwise = setSquareTo (b (x,y) + 1) (x,y) b
Now, I think this is doing only the calculations it needs to when finding the value of one square in a board generated by incSquare. However, it seems like finding the values of two adjacent squares one after the other wastes a lot of time doing the some of the same calculations in each case. Is this true?
If so is there a way a simple way of improving performance? Would something like
type Board = IntMap (IntMap Int)
using the strict version of IntMap be better? (How would I set every square to 0 initially in that case?)
This is the kind of thing I wrote data-inttrie for. It behaves just like a function from Int, except that it supports efficient single-point modifications through memoization.
You can initialize with any function f with fmap f identity, then use overwrite and modify to change it one value at a time.
Using a function as Board type is not such a good idea since the functions get more and more complicated when more calls to setSquareTo are made.
Then more and more space will be used to save this more and more complicated function. Also, when calling it with a value (x, y) for which setSquareTo hasn't been called for a long time, it takes a long time because the function first checks if the supplied parameter is one of the other coordinates.
So you should use Map (Int, Int) Int or your proposed IntMap (IntMap Int) instead as type for Board instead.
If you use Map (Int, Int) Int, you can use findWithDefault (x, y) 0 b instead of b (x, y) in this case to get 0 if this value doesn't yet exist in the map, so you don't have to initially set every value to 0 which isn't possible when you have an infinite board.
Related
I am new to Haskell and I am trying some stuff out. I am having some trouble comparing tuples elements.
Let's say I have a tuple [(1,3),(2,1),(4,4)].
I want to compare each pair index with each other and save some data into a counter value and return that value.
For example what I want is this:
Tuple: [(a,b),(c,d),(e,f)]
When a>b I want to add 3 to the counter.
When a==b I want to add 1 to the counter.
Otherwise add 0 to the counter. Same for (c,d) and (e,f).
After iterating through my tuples I want to return the counter.
So in my example I have tuple [(1,3),(2,1),(4,4)].
The function should do
Since 1<3 add 0 to counter.
Since 2>1 add 3 to counter.
Since 4=4 add 1 to counter.
And after all return 0+3+1 = 4.
Any ideas? Thank you in advance!
(Edit)
calculateWins :: [(Int,Int)]->Int
calculateWins d ((a,b) :xs) = x
where x
|a>b = 3
|a==b = 1
|otherwise = 0
This looks like the point system of a soccer cup (and some other sports). Instead of implementing a function that calculates the sum, we better first aim to calculate something that calculates the score for one such tuple, so something like:
score :: Ord a => (a, a) -> Int
By using a as type, we can use any type of values, as long as we can compare them (the Ord type constraint). So we can write something like:
score (x, y) = -- ...
now in case x > y, then the score is 3 points, in case x == y, then the score is 1 point, and finally in case x < y (otherwise), then the score is 0 points, so we can write it as:
score :: Ord a => (a, a) -> Int
score (x, y) | x > y = 3
| x == y = 1
| otherwise = 0
So now we can perform a map score to calcuate a list of scores, and by using sum, we can calculate the sum of those points, like:
calculateWins :: Ord a => [(a, a)] -> Int
calculateWins = sum . map score
Hint: use a function of type (a -> b) -> [a] -> [b] to transform the list of tuple into a list of your summands (3 or 1 or 0), and use another function of type [a] -> a to get the sum.
The Hoogle is a very nice site for looking up Haskell functions, both by name and by signature.
Please do try these things out before simply asking for the complete code; that helps neither of us.
I'm really struggling with Haskell atm.
It took me almost 6 hours to write a function that does what I want. Unfortunately I'm not satisfied with the look of it.
Could someone please give me any hints how to rewrite it?
get_connected_area :: Eq generic_type => [[generic_type]] -> (Int, Int) -> [(Int,Int)] -> generic_type -> [(Int,Int)]
get_connected_area habitat point area nullValue
| elem point area = area
| not ((fst point) >= 0) = area
| not ((snd point) >= 0) = area
| not ((fst point) < (length habitat)) = area
| not ((snd point) < (length (habitat!!0))) = area
| (((habitat!!(fst point))!!(snd point))) == nullValue = area
| otherwise =
let new_area = point : area
in
get_connected_area habitat (fst point+1, snd point) (
get_connected_area habitat (fst point-1, snd point) (
get_connected_area habitat (fst point, snd point+1) (
get_connected_area habitat (fst point, snd point-1) new_area nullValue
) nullValue
) nullValue
) nullValue
The function get's a [[generic_type]] (representing a landscape-map) and searches the fully connected area around a point that isn't equal to the given nullValue.
Eg.:
If the function gets called like this:
get_connected_area [[0,1,0],[1,1,1],[0,1,0],[1,0,0]] (1,1) [] 0
That literally means
0 1 0
1 1 1
0 1 0
1 0 0
Represents a map (like google maps). Start from the point (coordinates) (1,1) I want to get all coordinates of the elements that form a connected area with the given point.
The result therefore should be:
0 1 0
1 1 1
0 1 0
1 0 0
And the corresponting return value (list of coordinates of bold 1s):
[(2,1),(0,1),(1,2),(1,0),(1,1)]
One small change is that you can use pattern matching for the variable point. This means you can use (x, y) instead of point in the function declaration:
get_connected_area habitat (x, y) area nullValue = ...
Now everywhere you have fst point, just put x, and everywhere you have snd point, put y.
Another modification is to use more variables for subexpressions. This can help with the nested recursive calls. For example, make a variable for the inner-most nested call:
....
where foo = get_connected_area habitat (x, y-1) new_area nullValue
Now just put foo instead of the call. This technique can now be repeated for the "new" inner-most call. (Note that you should pick a more descriptive name than foo. Maybe down?)
Note that not (x >= y) is the same as x < y. Use this to simplify all of the conditions. Since these conditions test if a point is inside a bounding rectangle, most of this logic can be factored to a function isIn :: (Int, Int) -> (Int, Int) -> (Int, Int) -> Bool which will make get_connected_area more readable.
This would be my first quick pass through the function, and sort of the minimum that might pass a code review (just in terms of style):
getConnectedArea :: Eq a => [[a]] -> a -> (Int, Int) -> [(Int,Int)] -> [(Int,Int)]
getConnectedArea habitat nullValue = go where
go point#(x,y) area
| elem point area = area
| x < 0 = area
| y < 0 = area
| x >= length habitat = area
| y >= length (habitat!!0) = area
| ((habitat!!x)!!y) == nullValue = area
| otherwise =
foldr go (point : area)
[ (x+1, y), (x-1, y), (x, y+1), (x, y-1) ]
We bind habitat and nullValue once at the top level (clarifying what the recursive work is doing), remove indirection in the predicates, use camel-case (underdashes obscure where function application is happening), replace generic_type with a (using a noisy variable here actually has the opposite effect from the one you intended; I end up trying to figure out what special semantics you're trying to call out when the interesting thing is that the type doesn't matter (so long as it can be compared for equality)).
At this point there are lots of things we can do:
pretend we're writing real code and worry about asymptotics of treating lists as arrays (!!, and length) and sets (elem), and use proper array and set data structures instead
move your bounds checking (and possible null value checking) into a new lookup function (the goal being to have only a single ... = area clause if possible
consider improvements to the algorithm: can we avoid recursively checking the cell we just came from algorithmically? can we avoid passing area entirely (making our search nicely lazy/"productive")?
Here is my take:
import qualified Data.Set as Set
type Point = (Int, Int)
getConnectedArea :: (Point -> Bool) -> Point -> Set.Set Point
getConnectedArea habitat = \p -> worker p Set.empty
-- \p is to the right of = to keep it out of the scope of the where clause
where
worker p seen
| p `Set.member` seen = seen
| habitat p = foldr worker (Set.insert p seen) (neighbors p)
| otherwise = seen
neighbors (x,y) = [(x-1,y), (x+1,y), (x,y-1), (x,y+1)]
What I've done
foldr over the neighbors, as some commenters suggested.
Since the order of points doesn't matter, I use a Set instead of a list, so it's semantically a better fit and faster to boot.
Named some helpful intermediate abstractions such as Point and neighbors.
A better data structure for the habitat would also be good, since lists are linear time to access, maybe a 2D Data.Array—but as far as this function cares, all you need is an indexing function Point -> Bool (out of bounds and null value are treated the same), so I've replaced the data structure parameter with the indexing function itself (this is a common transformation in FP).
We can see that it would also be possible to abstract away the neighbors function and then we would arrive at a very general graph traversal method
traverseGraph :: (Ord a) => (a -> [a]) -> a -> Set.Set a
in terms of which you could write getConnectedArea. I recommend doing this for educational purposes—left as an exercise.
EDIT
Here's an example of how to call the function in terms of (almost) your old function:
import Control.Monad ((<=<))
-- A couple helpers for indexing lists.
index :: Int -> [a] -> Maybe a
index _ [] = Nothing
index 0 (x:_) = x
index n (_:xs) = index (n-1) xs
index2 :: (Int,Int) -> [[a]] -> Maybe a
index2 (x,y) = index x <=< index y
-- index2 uses Maybe's monadic structure, and I think it's quite pretty.
-- But if you're not ready for that, you might prefer
index2' (x,y) xss
| Just xs <- index y xss = index x xs
| otherwise = Nothing
getConnectedArea' :: (Eq a) => [[a]] -> Point -> a -> [a]
getConnectedArea' habitat point nullValue = Set.toList $ getConnectedArea nonnull point
where
nonnull :: Point -> Bool
nonnull p = case index2 p habitat of
Nothing -> False
Just x -> x /= nullValue
OK i will try to simplify your code. However there are already good answers and that's why i will tackle this with a slightly more conceptual approach.
I believe you could chose better data types. For instance Data.Matrix seems to provide an ideal data type in the place of your [[generic_type]] type. Also for coordinates i wouldn't chose a tuple type since tuple type is there to pack different types. It's functor and monad instances are not very helpful when it is chosen as a coordinate system. Yet since it seems Data.Matrix is just happy with tuples as coordinates i will keep them.
OK your rephrased code is as follows;
import Data.Matrix
gca :: Matrix Int -> (Int, Int) -> Int -> [(Int,Int)]
gca fld crd nil = let nbs = [id, subtract 1, (+1)] >>= \f -> [id, subtract 1, (+1)]
>>= \g -> return (f,g)
>>= \(f,g) -> return ((f . fst) crd, (g . snd) crd)
in filter (\(x,y) -> fld ! (x,y) /= nil) nbs
*Main> gca (fromLists [[0,1,0],[1,1,1],[0,1,0],[1,0,0]]) (2,2) 0
[(2,2),(2,1),(2,3),(1,2),(3,2)]
The first thing to note is, the Matrix data type is index 1 based. So we have our center point at (2,2).
The second is... we have a three element list of functions defined as [id, subtract 1, (+1)]. The contained functions are all Num a => a -> a type and i need them to define the surrounding pixels of the given coordinate including the given coordinate. So we have a line just like if we did;
[1,2,3] >>= \x -> [1,2,3] >>= \y -> return [x,y] would result [[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3]] which, in our case, would yield a 2 combinations of all functions in the place of the numbers 1,2 and 3.
Which then we apply to our given coordinate one by one with a cascading instruction
>>= \[f,g] -> return ((f . fst) crd, (g . snd) crd)
which yields all neighboring coordinates.
Then its nothing more than filtering the neighboring filters by checking if they are not equal to the nil value within out matrix.
This question already has answers here:
Sum of Squares using Haskell
(3 answers)
Closed 8 years ago.
Ok This is a homework question but I'm not asking for a solution to how its done
What I want to ask is what it is asking me to do?
The sum of the squares of integers in the range m:n (where m ≥ n) can
be computed recursively. If there is more than one number in the range
m:n, the solution is to add the square of m to the sum of the squares
in the rangem+1:n; otherwise there is only one number in the range
m:n, so m == n, and the solution is just the square of m.
a. Define the recursive function sumsquares to carry out this
computation. As always, draw up a series of test data showing the
expected output, and then test the function.
I know I have to write a recursive function called sumsquares but I dont quite understand what it means by "The sum of the squares of integers in the range m:n (where m ≥ n) can be computed recursively".
This is the code I have so far, Would this be correct??
sumsquares :: Integral a=> Int -> Int -> Int
sumsquares m n
|m > n = error "First number cannot be bigger than second number"
|m==n = m*n
|otherwise = m*n +sumsquares (m+1)n
Someone else came up with this answer
sumOfSquaresFast :: Integral a => a -> a -> a
sumOfSquaresFast lo hi
| lo > hi = error "sumOfSquaresFast: lo > hi"
| otherwise = ssq hi - ssq (lo - 1)
where ssq x = div (2 * x^3 + 3 * x^2 + x) 6
But I do not understand the bottom part, the ssq and the div functions?
From what I understand, you want to take two numbers, e.g. 1 and 10, square each number between them (inclusively), and then take the sum of that. So you'd want some function like
sumOfSquaresBetween :: Int -> Int -> Int
sumOfSquaresBetween m n = ???
Now, you have to use recursion, so this means that ??? is going to be some expression that uses sumOfSquaresBetween.
Now here's the trick: If you know sumOfSquares n n, then how would you find sumOfSquares (n - 1) n? What about sumOfSquares (n - 2) n? Can you generalize this all the way to sumOfSquares m n for m <= n? If so, then you've just performed your desired algorithm, but in reverse.
Hope this hint helps.
"The sum of the squares of integers in the range m:n (where m ≥n) can be computed recursively."
Let's break this apart....
"integers in the range m:n"
is the set of integers starting from m, going to n
[m, m+1, m+2, ....n]
ie-
integers in the range 4:8 = [4,5,6,7,8]
"squares of...."
As you probably know, the square of a number x is x*x, so
squares of integers in the range 4:8 = [16, 26, 36, 49, 64]
"The sum of...."
add them
The sum of the squares of integers in the range 4:8 = 16+26+36+49+64
".... can be computer recursively"
Well, you have to understand recursion to get this....
Any function that contains itself in the definition is recursive. Of course you have to be careful, if done incorrectly, a recursive function could lead to infinite loops....
For Ints, (N-1) recursion is common.... If you can use the calculation for (N-1) to evaluate the calculation for N, the computer can run down the numbers until a known value is hit (typically 0). This is better seen with an example.
let func n = sum of integers from 0 to n
(this is like your problem, but without the squares part)
if you know the value of func (n-1), you can easily compute the value of func n
func n = n + func (n-1)
func 0 = 0
The computer will use func 0 to compute func 1, func 1 to compute func 2, etc, all the way to N.
Recursion has two common (but actually pretty different) uses... First, as shown above, it allows for very clean function definitions.
Secondly, it is often used in mathematics to prove truths over all integers (ie- to prove something is true for all ints, prove it is true for 0, then prove if it is true for N, it is true for N+1....).
Really, the best way to solve this problem is also the easiest: use library functions.
sumsquares :: Integral a => a -> a -> a
sumsquares m n = sum (map (^2) (enumFromTo n m))
You just enumerate the numbers from n to m, square each of them, and take the sum of the results. Trying to solve this problem in with direct recursion just makes things needlessly complicated.
Exercise: Write your own versions of the library functions used in this answer.
-- | Generate the list of all values in the given range. Result is inclusive.
enumFromTo :: Enum a => a -> a -> [a]
-- | Apply a function individually to each element of the argument list,
-- and collect the results as a list, respecting the order of the original.
map :: (a -> b) -> [a] -> [b]
-- | Calculate the sum of a list of numbers.
sum :: Num a => [a] -> a
I'm looking through a past exam paper and don't understand how to convert Int to [Int].
For example, one of the questions asks us to produce a list of all the factors of a whole number excluding both the number itself and 1.
strictFactors Int -> [Int]
strictFactors x = ???
I'm not asking for anyone to do this question for me! I just want to know how I'd convert an integer input to a list of integer output. Thanks!
Perhaps it would be easiest to have a look at some similar code. As requested, I won't give you the answer, but you should be able to use these ideas to do what you want.
Brute force
Here we're just going to use all the pairs of numbers between 1 and x to test if we can make x as the sum of two square numbers:
sumOfSquares :: Int -> [Int]
sumOfSquares x = [ (a,b) | a <- [1..x], b <- [a..x], a^2 + b^2 == x]
You call this like this:
ghci> asSumOfSquares 50
[(1,7),(5,5)]
because 50 = 1^2+7^2 and also 50 = 5^2 + 5^2.
You can think of sumOfSquares as working by first taking an a from the list [1..x] of numbers between 1 and x and then another between that and x. It then checks a^2 + b^2 == x. If that's True, it adds (a,b) to the resulting list.
Generate and check
This time let's generate some single numbers then check whether they're a multiple of another. This will calculate the least common multiple (lcm). For example, the least common multiple of 15 and 12 is 60, because it's the first number that's in both the 15 and 12 times tables.
This function isn't of the type you want but it uses all the techniques you want.
lcm :: Int -> Int -> Int
lcm x y = head [x*a | a <- [1..], (x*a) `mod` y == 0]
You can call that like this:
ghci> lcm 12 15
60
This time the list of numbers [1..] is (in principle) infinite; good job we're just picking the first one with head!
(x*a) `mod` y == 0 does the checking to see whether the number x*a is a multiple of y (mod gives the remainder after division). That's a key idea you should use.
Summary
Use a <- [1..end] to generate numbers, test them with a True/False expression (i.e. a Bool), perhaps using the mod function.
I'm quite new at Haskell but can think of a myriad ways of "converting" an Int to a list containing that same Int:
import Control.Applicative (pure)
sane_lst :: Int -> [Int]
sane_lst x = [x]
lst :: Int -> [Int]
lst x = take 1 $ repeat x
lst' :: Int -> [Int]
lst' = replicate 1
lst'' :: Int -> [Int]
lst'' = return
lst''' :: Int -> [Int]
lst''' = pure
lst'''' :: Int -> [Int]
lst'''' x = enumFromTo x x
I guess the point here is that you don't "convert" to a list, you rather "construct" the list you need. The staightforward strategy for the kind of question you posed is to find something that will give you a suitable starting list to work with based on your parameter, then filter, fold or comprehend as needed.
For example when I say:
lst x = take 1 $ repeat x
I'm first constructing an infinite list repeating the value I passed in, and then taking from it a list containing just the first element. So if you think about what kind of list you need to start with to find the solution to your problem you'll be halfway there.
If your only goal is to convert between the types (for now) then strictFactors x = [x] is the most canonical answer. This function is also called pure since [] is what's known as an Applicative and return since [] is known as a Monad.
I'm very new to haskell, writing a simple code that returns how many inputs are larger than their average value. I got error:
ERROR file:.\AverageThree.hs:5 - Type error in application
* Expression : x y z
Term : x
Type : Int
* Does not match : a -> b -> c
Code:
averageThree :: Int -> Int -> Int -> Float
averageThree x y z = (fromIntegral x+ fromIntegral y+ fromIntegral z)/3
howManyAverageThree ::Int -> Int -> Int -> Int
howManyAverageThree x y z = length > averageThree
Anyone help me?
The trouble you're having comes from a few places.
First, you aren't applying either function, length or averageThree - and hence also not using your arguments to howManyAverageThree.
Second, the type of length is [a] -> Int. As you don't have a list here, you either have to use a different function, or make a list.
If I understand your desired algorithm correctly, you are going to need to do a few things:
Apply x y and z to averageThree.
Use the filter function, comparing this computed average with each passed in parameter; this will result in a list.
Find the length of the resulting list.
The code I dashed off to do this follows:
howManyAverageThree ::Int -> Int -> Int -> Int
howManyAverageThree x y z = length $ filter (> avg) the_three
where avg = averageThree x y z
the_three = [fromIntegral x,fromIntegral y,fromIntegral z]
This takes advantage of a couple of neat features:
Currying, sometimes called "partial function application". That's what I was using with (> avg); normally, the infix function > takes two parameters of the same type, and returns a Bool - by wrapping in parenthesis and providing an expression on one side, I have partially applied it, which allows it to be used as a filter function
The where keyword. I used this to clean it all up a little and make it more readable.
The filter function, which I mentioned above.
Function application using $. This operator just changes the function application from left-associative to right-associative.
There are a number of problems here:
length doesn't do what you want it to. length returns the length of a list, and there are no lists in your howManyAvergageThree
averageThree returns a Float. howManyAverageThree needs to account for that. Specifically, > needs its arguments to be of the same type.
The call to averageThree in the second function needs some arguments.
Here's a working version:
howManyAverageThree x y z = length [ i | i <- [x, y, z], fromIntegral i > avg]
where avg = averageThree x y z