Center a triangle (HASKELL) - haskell

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
*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
* * * * * * * *
* * * * * * * * *
* * * * * * * * * *

Related

Making a bottomleftcorner triangle in Haskell with IO()

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
* * * *
* * *
* *
*

How to print several triangles in one line (HASKELL)

I have this self-defined IO() Triangle, which has each row of a triangle as an element in a list:
import Data.List ( intersperse )
type Triangle = Char -> Int -> [String]
centeredTriangle :: Triangle
centeredTriangle c n = [replicate (n-i) ' ' ++ intersperse ' ' (replicate i c) | i <- [0 .. n]]
Output:
Ok, one module loaded.
ghci> centeredTriangle '*' 6
[" "," *"," * *"," * * *"," * * * *"," * * * * *","* * * * * *"]
When I run my main function, I use unlines to print out the triangle like so:
triangles :: Int -> Int -> Int -> IO()
triangles a b c = do
putStr $ unlines $ centeredTriangle '*' a
putStr $ unlines $ centeredTriangle '*' b
putStr $ unlines $ centeredTriangle '*' c
Output:
ghci> triangles 1 2 3
*
*
* *
*
* *
* * *
I want to print the triangles on the same line, like so:
ghci> triangles 1 2 3
*
* * *
* * * * * *
I realise it may be a bigger task than I first anticipated, but my first thought was to use centeredTriangle to get the bottom line (last element of the list) of each triangle, and put them toghether in a new string which I then put as the last element in a new list of strings. I thought If I do this for each element (starting from the last) and up to the top I can print the triangles in the same line using my main funtion. How do I achieve this?
Using type Triangle = [String],
Write a function boundingBox :: Triangle -> (Int,Int).
Write a function maxBoundingBox :: [Triangle] -> (Int,Int).
Write a function putInBox :: Triangle -> (Int,Int) -> Triangle.
Write a function makeSameSize :: [Triangle] -> [Triangle].
Write a function sideToSide :: Triangle -> [String] -> [String].
Use it in foldr to conjoin all the resized Triangles together.
Some of the above functions aren't needed if you are the one creating these triangles in the first place. Then you just know the bounding box of the triangle you would create from the given parameters.

Define the function squarefact::Int -> Int that computes for any positive integer n the squared factorial (n!)^2 == (1 * ...* n)^2

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.

Haskell - Parse error on input '='

getFloat :: IO Float
main = do
putStr "Enter question number: "
xs <- getLine
if (xs == 3)
then do
main2
else
main2
main2 =
pricePizza :: Double -> Double -> Double
pricePizza x y = priceBase x + priceTopping x y * 1.6
priceBase x = (3.14 * (x * 0.5) * x) * 0.001
priceTopping x y = ((3.14 * (x * 0.5) * x) * 0.0002) * y
Why doesn't this work?
You can't have a line like:
main2 =
on its own. It's a syntax error.
If you want to have keep some partially defined functions that you are still working on, you can use undefined:
main2 = undefined
or else put in some dummy code:
main2 =
Once that is fixed, you have two more problems:
You have a type for getFloat, but no definition. If you plan to define it later then you can give it an undefined value, otherwise you should remove it.
The type of xs is String so you can't compare it to 3, which is and Int. You can just use a string literal instead.
I think this is what you were trying to do, and compiles:
main :: IO ()
main = do
putStr "Enter question number: "
xs <- getLine
if (xs == "3")
then do
main2
else
main2
main2 = putStrLn "main 2"
pricePizza :: Double -> Double -> Double
pricePizza x y = priceBase x + priceTopping x y * 1.6
priceBase x = (3.14 * (x * 0.5) * x) * 0.001
priceTopping x y = ((3.14 * (x * 0.5) * x) * 0.0002) * y

Print Diamond Pattern using Haskell

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 (++)

Resources