I need to write a Haskell program that will generate a diamond output recursively.
Here is some sample output for given input
input : 1
output :
*
* *
*
input : 2
output :
*
* *
*
* *
* * * *
* *
*
* *
*
input : 3
output :
*
* *
*
* *
* * * *
* *
*
* *
*
* *
* * * *
* *
* * * *
* * * * * * * *
* * * *
* *
* * * *
* *
*
* *
*
* *
* * * *
* *
*
* *
*
I wrote following functions:
next 0 = [1,0,1]
next n = map (+3^n) (next (n-1)) ++ next (n-1) ++ map (+3^n) (next (n-1))
lpad n = map (++"*") (zipWith ($) (map (take)(next (n-1))) ((repeat(repeat ' '))))
pretty n = putStrLn $ intercalate "\n" $ lpad n
which gives following outputs:
pretty 1
*
*
*
pretty 2
*
*
*
*
*
*
*
*
*
Can anyone help me with the remaining halves? Thanks in advance.
For n==0, next n describes the whole picture up to mirroring. This is not the case anymore for greater n. So, in a first step, we change the next function to output a symmetric picture:
mmap = map . map
next :: Int -> [[Int]]
next 0 = [[1],[0,2],[1]]
next n = sn ++ map (\a -> a ++ map (+2*3^n) a) nn ++ sn
where
nn = next (n - 1)
sn = mmap (+3^n) nn
Now, next n describes the positions of all stars. To print them, we first compute the relative distances.
diffs :: [Int] -> [Int]
diffs (x:xs) = x: diffs' x (xs)
where
diffs' x (y:ys) = y - x - 1 : diffs' y ys
diffs' _ [] = []
diffs [] = []
lpad :: Int -> [[Char]]
lpad = map (concatMap $ \n -> replicate n ' ' ++ "*") . map diffs . next'
Applied to one line, diffs returns the list of the number of spaces we need to put before each star and lpad generates the picture from that. Print it as before:
pretty :: Int -> IO ()
pretty n = putStrLn $ unlines $ lpad n
I liked the task, so I wrote an alternative solution.
We could build it up, a bit like you would with a pretty printer. Look into the pretty package to take these ideas and use them properly, but let's stick to plain old [String] for this.
First let's make a blank grid
blank :: Int -> [String]
blank n = replicate (3^n) $ replicate (3^n) ' '
Then let's define a diamond.
diamond :: Int -> [String]
diamond 0 = ["*"]
diamond n = let
o = diamond (n-1)
x = blank (n-1) in
joinMatrix [[x,o,x]
,[o,x,o]
,[x,o,x]]
But how can we join this matrix of [String] together?
First get all the Strings that should be concatenated together next to each other instead of under each other using transpose, then concat them all:
joinLine :: [[String]] -> [String]
joinLine = map concat.transpose
To do that to a whole matrix we need to join the lines on each row, then concat all the lines together into one list of lines:
joinMatrix :: [[[String]]] -> [String]
joinMatrix = concat.map joinLine
helper functions for printing:
put = mapM_ putStrLn
d n = put $ diamond n
You could argue that the numerical solution is more efficient, and it is, but d 4 is the largest that fits on my screen and isn't slow. You could also argue that this solution is clearer.
*Main> d 0
*
*Main> d 1
*
* *
*
*Main> d 2
*
* *
*
* *
* * * *
* *
*
* *
*
(It works for higher n too, but they would make this post unnecessarily long on the page.)
This is derived from AndrewC's solution. The space blocks are recursively generated and I prefer to use operators to make the code clearer:
diamond
= putStr
. unlines
. fst
. (iterate f (["*"], [" "]) !!)
where
f (d, e)
= ( e + d + e
++ d + e + d
++ e + d + e
, e + e + e
++ e + e + e
++ e + e + e
)
(+) = zipWith (++)
A generalization.
If we would like to have this:
+
- -
+
- -
+ + + +
- -
+
- -
+
- -
+ + + +
- -
+ + + +
- - - - - - - -
+ + + +
- -
+ + + +
- -
+
- -
+
- -
+ + + +
- -
+
- -
+
then the solution is star 3 where
star
= putStr
. unlines
. (\(d, p, e) -> d)
. (iterate f (["-"], ["+"], [" "]) !!)
where
f (d, p, e)
= ( e + p + e
++ d + e + d
++ e + p + e
, e + d + e
++ p + e + p
++ e + d + e
, e + e + e
++ e + e + e
++ e + e + e
)
(+) = zipWith (++)
Related
I am trying to understand why my code doesn't work:
writeRow :: Int -> IO()
writeRow x = putStr(concat (replicate x "* "))
triangle :: Int -> IO()
triangle x = do
writeRow x
putStr ""
triangle x-1
My thinking is, that writeRow creates a row of x times " * ", so if x = 4, triangle 4 will write
* * * *
As triangle is called recursivly with x -1, the next line will be:
* * *
And so on ... until:
* * * *
* * *
* *
*
But it just outputs it all on one line:
* * * * * * * *
What seems to be the issue? :D
putStr only prints the string, it does not write a new line, you should use putStrLn. Furthermore you should use triangle (x-1) so with parenthesis around the x-1 part, and specify a base case for the recursion with the triangle:
writeRow :: Int -> IO()
writeRow x = putStr(concat (replicate x "* "))
triangle :: Int -> IO()
triangle x | x <= 0 = pure ()
triangle x = do
writeRow x
putStrLn ""
triangle (x-1)
With these modifications, we obtain:
Prelude> triangle 4
* * * *
* * *
* *
*
Inspired by this question, I have made this code which prints out triangles:
type TriangleMaker = Char -> Int -> [String]
topLeftTriangle :: TriangleMaker
topLeftTriangle c n = [replicate i c | i <- [1 .. n]]
centeredTriangle :: TriangleMaker
centeredTriangle c n = [replicate (n-i) ' ' ++ replicate i c | i <- [0 .. n]]
getType :: IO TriangleMaker
getType = do
let menu = [topLeftTriangle, centeredTriangle]
putStr $ unlines [
"What type of triangle do you want to print? (type 1 and then type the int size)",
"1) Top Left",
"2) Centered"]
line <- getLine
return (menu !! ((read line :: Int) - 1))
trekant :: IO()
trekant = do
triangle <- getType
size <- getLine
putStr $ unlines $ triangle '*' (read size :: Int)
It gives me this output in ghci:
Ok, one module loaded.
ghci> trekant
What type of triangle do you want to print? (type 1 and then type the int size)
1) Top Left
2) Centered
1
6
*
**
***
****
*****
******
ghci> trekant
What type of triangle do you want to print? (type 1 and then type the int size)
1) Top Left
2) Centered
2
6
*
**
***
****
*****
******
I want to make it so that I can use a string as input instead of a char, like so:
trekant :: IO()
trekant = do
triangle <- getType
size <- getLine
putStr $ unlines $ triangle " *" (read size :: Int)
That way, (I think) I'll get a centered triangle as output:
ghci> trekant
What type of triangle do you want to print? (type 1 and then type the int size)
1) Top Left
2) Centered
2
6
*
* *
* * *
* * * *
* * * * *
* * * * * *
Or am I way off here? How can I re-write this so that the triangle is centered?
In case you want to generate a triangle in the center, you should add spaces between two stars, this thus means that the string looks like:
centeredTriangle :: TriangleMaker
centeredTriangle c n = [replicate (n-i) ' ' ++ concat (replicate i [c, ' ']) | i <- [0 .. n]]
We thus generate a string where we have n-i spaces followed by n times the "* " string.
Perhaps it is more elegant to work with intersperse :: a -> [a] -> [a] where we intersperse a list of '*' characters with spaces:
import Data.List(intersperse)
centeredTriangle :: TriangleMaker
centeredTriangle c n = [replicate (n-i) ' ' ++ intersperse ' ' (replicate i c) | i <- [0 .. n]]
This then produces:
ghci> trekant
What type of triangle do you want to print? (type 1 and then type the int size)
1) Top Left
2) Centered
2
6
*
* *
* * *
* * * *
* * * * *
* * * * * *
ghci> trekant
What type of triangle do you want to print? (type 1 and then type the int size)
1) Top Left
2) Centered
2
10
*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
* * * * * * * *
* * * * * * * * *
* * * * * * * * * *
I am trying to define a function that computes for any positive integer the square of its factorial
(I am a beginner in Haskell any tips or help is appreciated)
I have tried a couple different ways one i believe to work and one definition i don't understand why it doesn't work
Function i believe works:
squarefact:: Int -> Int
squarefact 0 = 1
squarefact n = n * n * squarefact(n-1)
Function I don't understand why it doesn't work:
squarefact:: Int -> Int
squarefact 0 = 1
squarefact n = (n * squarefact(n-1) ) * (n * squarefact(n-1) )
An explanation and walk through of the dunctions defined would help me understand them better thanks.
The equation
squarefact n = (n * squarefact(n-1) ) * (n * squarefact(n-1) )
could be rewritten in mathematical notation as
(n!)^2 = n * ((n-1)!)^2 * n * ((n-1)!)^2
but this identity is incorrect. The right hand side includes factors 1,2,....,n-1 four times instead of only two, as in the left hand side.
By comparison,
squarefact n = n * n * squarefact(n-1)
is correct, since on both sides all the factors occur exactly twice.
A factorial function can be defined in Haskell as
factorial n = product [1..n]
(where product is a function that calculates the product of all the numbers in a given list.)
Hence,
squarefact n = square (factorial n) =
= square (product [1..n])
= product [1..n] * product [1..n]
= 1 * 2 * 3 * ... * (n-1) * n *
1 * 2 * 3 * ... * (n-1) * n
= product [1..(n-1)] * n * product [1..(n-1)] * n
= n * n * square (product [1..(n-1)])
= n * n * squarefact (n-1)
The equality re-writes break down for n=0 ( squarefact 0 /= 0 * 0 * squarefact (-1) ), so it must be handled as a special case.
I've started using Haskell lately, and defined this seemingly simple function:
f 0 = 1
f x = x * f x - 1
However, it results in this:
GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for help
Prelude> f 0 = 1
Prelude> f x = x * f x - 1
Prelude> f 10
*** Exception: stack overflow
Prelude>
Your factorial seems innocent, but it isn't. It's parsed like this:
f 0 = 1
f x = x * (f x) - 1
What happens if we use f 1?
f 1 = 1 * (f 1) - 1 = 1 * (1 * (f 1) - 1) - 1
= 1 * (1 * (1 * (f 1) - 1) - 1) - 1
= 1 * (1 * (1 * (1 * (f 1) - 1) - 1) - 1) - 1
= ...
I'm going to stop here. This will never end. It will build up a stack of parentheses, and at some the whole tower collapses and you end up with a stack overflow.
You have to use parentheses:
f 0 = 1
f x = x * f (x - 1)
Now we get the correct result:
f 1 = 1 * f (1 - 1) = 1 * f 0 = 1 * 1 = 1
Keep in mind that this works only in an implementation file. In GHCi you have to use multi-line mode or a semicolon:
ghci> f 0 = 1; f x = x * f (x - 1)
ghci> -- or
ghci> :{
ghci| f 0 = 0
ghci| f x = x * f (x - 1)
ghci| :}
Otherwise later definitions will shadow earlier ones. Note that your prompt might differ.
I'm currently trying to calculate the following sum:
sum2015 :: Integer->Integer->Integer
sum2015 m n
| m>n = 0
| otherwise = (m+m)^n + sum2015 (m+1) n
As an example, sum2015 0 1 should return 1. However, it returns 2. What did I do wrong?
You're not calculating that sum. Note that m in (m + i)^n must stay fixed, but you use a new m here:
| otherwise = … + sum2015 (m+1) n
-- ^^^^^
-- oh oh
Therefore you get:
sum2015 0 1
= (0 + 0)^1 + sum2015 (0 + 1) 1
= (0 + 0)^1 + (1 + 1)^1 + sum2015 (1 + 1) 1
= (0 + 0)^1 + (1 + 1)^1 + 0
= 0 + 2
= 2
Instead, calculate all (m + i)^n and sum them afterwards:
sum2015 :: Integer -> Integer -> Integer
sum2015 m n = sum . map (\i -> (m + i) ^ n) $ [m..n]
Or, if you're not allowed to use that, use a worker:
sum2015 :: Integer -> Integer -> Integer
sum2015 m n = go m
where go i = ...
I can offer this option:
sum2015 m n = sum [(m + i) ** n | i <- [m..n]]
Firstly, I created list of numbers from m to n "[m..n]".
After for each i in this list, I computing terms of the sum.
Finally, just use "sum" function for obtained result list.
'**' - Pow function