"drawing" char/string shapes by a variable diagonal length in haskell - string

I'm looking for a function (let's name it diamond) that "draws" a diamond-shaped "object" by defining only the length of it's diagonal (e.g.: as shown below, so the length of the diagonal in this case is 5 "*" but only 3 are visible):
Main> diamond 5
Output:
*
***
*****
***
*
I have these functions:
stars x
| (x mod 2 == 1) = (firstHalf x) ++ [x] ++ reverse(firstHalf x)
| otherwise = (firstHalf x) ++ reverse(firstHalf x)`
firstHalf x = take (x div 2) (iterate (2+) 1)
space x = map (div 2) (map ((x+1)-) (stars x))
Example output:
space 5 = [2,1,0,1,2]
stars 5 = [1,3,5,3,1]
This function might work but I don't know how to fix this error:
Type error in application:
Expression : replicate (stars x) ['*']
Term : stars x
Type : [Int]
Does not match : Int
diamond x = mapM_ putStrLn $ (replicate (space x) [' ']) ++ (replicate (star x) ['*'])
And I guess even if this error was fixed it would still need a tweak that would join those two lists to get the desired result. Any ideas?

You can generate a number of stars with replicate:
ghci> replicate 5 '*'
"*****"
You can also do this with any other character, such as a space (' ').
You can print a line to the screen with putStrLn:
ghci> putStrLn (replicate 5 '*')
*****
Here is a program that generates the star above:
main = do
putStrLn $ replicate 2 ' ' ++ replicate 1 '*'
putStrLn $ replicate 1 ' ' ++ replicate 3 '*'
putStrLn $ replicate 0 ' ' ++ replicate 5 '*'
putStrLn $ replicate 1 ' ' ++ replicate 3 '*'
putStrLn $ replicate 2 ' ' ++ replicate 1 '*'
You can define functions with =:
hello x = putStrLn $ "Hello " ++ x
main = do
hello "Bob" -- prints "Hello Bob"
(If you do this from the ghci prompt, you have to say let first: eg. let hello x = putStrLn $ "Hello " ++ x)
I don't know why I spent so much time on this question, but I felt like it. Typically we want questions to provide some evidence that you have spent some time trying to solve the problem before asking for help. Merry Christmas...
I have given you all the pieces. Now you have to put them together.

Related

Print Custom String With the Sum of Three Lists

When I run the following code:
main = do
let smallTriplets xs ys zs = [ (x, y, z) | x <- xs, y <- ys, z <- zs, let sum = x + y + z, sum <= 10]
print (smallTriplets [1,2] [3,4] [5,6])
It gives the output:
[(1,3,5),(1,3,6),(1,4,5),(2,3,5)]
However, I want smallTriplets to print the sum with some customization. To be more specific, it will be better if I could replace let sum = x + y + z in smallTriplets with some code so that it gives output like:
Sum is 1+3+5 = 9
Sum is 1+3+6 = 10
Sum is 1+4+5 = 10
Sum is 2+3+5 = 10
I am expecting that code to have a string like "Sum is " ++ show(x) ++ "+" ++ show(y) ++ "+" ++ show(z) ++ " = " ++ show(x + y + z) ++ "\n"
How can I do that?
If this is not possible then please show me how to print:
Sum is 1+3+5 = 9
Sum is 1+3+6 = 10
Sum is 1+4+5 = 10
Sum is 2+3+5 = 10
What's the problem of writing "Sum is " ++ show x ++ "+" ++ show y ++ "+" ++ show z ++ " = " ++ show sum instead of (x, y, z)?
You could like this
main = do
let helper x y z s = "Sum is " ++ show x ++ "+" ++ show y ++ "+" ++ show z ++ " = " ++ show s
let smallTriplets xs ys zs = [ helper x y z sum | x <- xs, y <- ys, z <- zs, let sum = x + y + z, sum <= 10]
putStr $ unlines $ smallTriplets [1,2] [3,4] [5,6]
Here, smallTriplets returns a [String] instead of a [(,,)]; unlines converts the [String] to a String with embedded \ns; finally, putStr prints the string.
This is a quick and dirty solution which alters the function smallTriplets, so if you planned to use the original result in other ways this solution will not help.
If your aim is to log things you do, then a more complex solution is needed. Maybe using the writer monad?

My first haskell: best *inline* way to make a "natural language" listing of items? (like "1, 2, 3 and 4")

For my first line of Haskell I thought it'd be a nice case to produce a "natural listing" of items (of which the type supports show to get a string representation). By "natural listing" I mean summing up all items separated with , except the last one, which should read and lastitem. Ideally, I'd also like to not have a , before the "and".
To spice it up a bit (to show off the compactness of haskell), I wanted to have an "inline" solution, such that I can do
"My listing: " ++ ... mylist ... ++ ", that's our listing."
(Obviously for "production" making a function for that would be better in all ways, and allow for recursion naturally, but that's the whole point of my "inline" restriction for this exercise.)
For now I came up with:
main = do
-- hello
nicelist
nicelist = do
let is = [1..10]
putStrLn $ "My listing: " ++ concat [ a++b | (a,b) <- zip (map show is) (take (length is -1) $ repeat ", ") ++ [("and ", show $ last is)]] ++ ", that's our listing."
let cs = ["red", "green", "blue", "yellow"]
putStrLn $ "My listing: " ++ concat [ a++b | (a,b) <- zip (map show cs) (take (length cs -1) $ repeat ", ") ++ [("and ", show $ last cs)]] ++ ", that's our listing."
but this hardly seems optimal or elegant.
I'd love to hear your suggestions for a better solution.
EDIT:
Inspired by the comments and answer, I dropped the inline requirement and came up with the following, which seems pretty sleek. Would that be about as "haskellic" as we can get, or would there be improvements?
main = do
putStrLn $ "My listing: " ++ myListing [1..10] ++ ", that's the list!"
putStrLn $ "My listing: " ++ myListing ["red", "green", "blue", "yellow"] ++ ", that's the list!"
myListing :: (Show a) => [a] -> String
myListing [] = "<nothing to list>"
myListing [x] = "only " ++ (show x)
myListing [x, y] = (show x) ++ " and " ++ (show y)
myListing (h:t) = (show h) ++ ", " ++ myListing t
Here's how I would write it:
import Data.List
niceShow' :: [String] -> String
niceShow' [] = "<empty>"
niceShow' [a] = a
niceShow' [a, b] = a ++ " and " ++ b
niceShow' ls = intercalate ", " (init ls) ++ ", and " ++ last ls
niceShow :: [String] -> String
niceShow ls = "My listing: " ++ niceShow' ls ++ ", that's our listing."
niceList :: IO ()
nicelist = do
putStrLn $ niceShow $ show <$> [1..10]
putStrLn $ niceShow ["red", "green", "blue", "yellow"]
Steps:
Create niceShow to create your string
Replace list comprehensions with good old function calls
Know about intercalate and init
Add type signatures to top levels
Format nicely
niceShow can only be inlined if you know the size of the list beforehand, otherwise, you'd be skipping the edge cases.
Another way to state the rules for punctuating a list (without an Oxford comma) is this:
Append a comma after every element except the last two
Append “and” after the second-to-last element
Leave the final element unchanged
This can be implemented by zipping the list with a “pattern” list containing the functions to perform the modifications, which repeats on one end. We want something like:
repeat (<> ",") <> [(<> " and"), id]
But of course this is just an infinite list of the comma function, so it will never get past the commas and on to the “and”. One solution is to reverse both the pattern list and the input list, and use zipWith ($) to combine them. But we can avoid the repeated reversals by using foldr to zip “in reverse” (actually, just right-associatively) from the tail end of the input. Then the result is simple:
punctuate :: [String] -> [String]
punctuate = zipBack
$ [id, (<> " and")] <> repeat (<> ",")
zipBack :: [a -> b] -> [a] -> [b]
zipBack fs0 = fst . foldr
(\ x (acc, f : fs) -> (f x : acc, fs))
([], fs0)
Example uses:
> test = putStrLn . unwords . punctuate . words
> test "this"
this
> test "this that"
this and that
> test "this that these"
this, that and these
> test "this that these those them"
this, that, these, those and them
There are several good ways to generalise this:
zipBack is partial—it assumes the function list is infinite, or at least as long as the string list; consider different ways you could make it total, e.g. by modifying fs0 or the lambda
The punctuation and conjunction can be made into parameters, so you could use e.g. semicolons and “or”
zipBack could work for more general types of lists, Foldable containers, and functions (i.e. zipBackWith)
String could be replaced with an arbitrary Semigroup or Monoid
There’s also a cute specialisation possible—if you want to add the option to include an Oxford comma, its presence in the “pattern” (function list) depends on the length of the final list, because it should not be included for lists of 2 elements. Now, if only we could refer to the eventual result of a computation while computing it…

How are expressions allowed inside Haskell do blocks

In the following code, line 4, I have an expression sandwiched between two IO actions in a do block:
1 doubleX :: (Show x, Num x) => x -> IO ()
2 doubleX x = do
3 putStrLn ("I will now double " ++ (show x))
4 let double = x * 2
5 putStrLn ("The result is " ++ (show double))
I understand do notation as chaining monadic operations together using >>= or >>. But how does that work when you have an expression in between? You couldn't just glue lines 3-5 together using >>.
I'm going to crib from my very similar answer here (though probably not a duplicate since that question doesn't explicitly deal with let).
The Report gives a full translation from do syntax into kernel Haskell; the parts relevant to your question are:
do {e} = e
do {e;stmts} = e >> do {stmts}
do {let decls; stmts} = let decls in do {stmts}
So your code desugars like this:
doubleX x = do
putStrLn ("I will now double " ++ (show x))
let double = x * 2
putStrLn ("The result is " ++ (show double))
==> do {e;stmts} rule
doubleX x =
putStrLn ("I will now double " ++ (show x)) >> do
let double = x * 2
putStrLn ("The result is " ++ (show double))
==> do {let decls; stmts} rule
doubleX x =
putStrLn ("I will now double " ++ (show x)) >>
let double = x * 2 in do
putStrLn ("The result is " ++ (show double))
==> do {e} rule
doubleX x =
putStrLn ("I will now double " ++ (show x)) >>
let double = x * 2 in
putStrLn ("The result is " ++ (show double))

Accessing a list entry and showing its values

I have a function
(.#.) :: [a] -> Integer -> a -- 1-indexing with 'Integer'
xs .#. j = xs !! (fromIntegral $ j-1)
showIntegers :: [Integer] -> String
showIntegers r = let
str = concat $ "List: " : [r (.#.) j | j <- [1..length r]]
How can I show r (.#.) j as a Char/String rather than an integer? I tried using show, but it gave me an error.
Here is an example of how I used show:
str = concat $ "List: " : [show $ r (.#.) j | j <- [1..length r]]
Example input and output:
> showIntegers [1,2,3]
List: 1 2 3
You should just use Data.List.intercalate or even better use unwords.
import Data.List
showIntegers :: [Integer] -> String
showIntegers r = "List: " ++ intercalate " " $ map show r
--showIntegers r = "List: " ++ unwords $ map show r
EDIT: In either case you should avoid using !! especially to enumerate the original list.
First I would get rid of .#. it is just going to confuse you to use a different numbering system, best to rip that bandaid off.
Next realize that [show $ r !! j <- 0 .. length r - 1] is the same as map show r (and the latter is standard).
Now going with that you have: concat $ "List: " : (map show r) which creates List: 123 because we lost the spaces.
We could reproduce the spaces but what is the difference between using intercalate and concat? Honestly the best solution without using intercalate would be to reproduce intercalate (whose source code is available on Hackage).
Just remove the parenthesis around (.#.) and it works.
If you have an infix operator !#$ , with something before and after it, e.g. x !#$ y, you must not use parentheses. In the other cases, add parentheses, like in the type declaration.
(this technically answers the question, but Guvante's advice is better.)

Is there a better way of doing this in Haskell?

I have written the following to assist grand kids with their home schooling work and to keep mind working by learning how to program (I thought haskell sounded awesome).
main :: IO ()
main = do
putStrLn "Please enter the dividend :"
inputx <- getLine
putStrLn "Please enter the divisor :"
inputy <- getLine
let x = (read inputx) :: Int
let y = (read inputy) :: Int
let z = x `div` y
let remain = x `mod` y
putStrLn ( "Result: " ++ show x ++ " / " ++ show y ++ " = " ++ show z ++ " remainder " ++ show remain )
putStrLn ( "Proof: (" ++ show y ++ " x " ++ show z ++ ") = " ++ show (y * z) ++ " + " ++ show remain ++ " = " ++ show ((y * z) + remain))
putStrLn ( "Is this what you had? ")
Is their a neater/nicer/better/more compact way of doing this?
It would benefit from a key principle: separate your pure code from your IO as much as possible. This will let your programs scale up and keep main breif. Lots of let in a big main isn't a very functional approach and tends to get much messier as your code grows.
Using a type signature and readLn which is essentially fmap read getLine helps cut down some cruft. (If you're not familiar with fmap, visit the question How do functors work in haskell?. fmap is a very flexible tool indeed.)
getInts :: IO (Int, Int)
getInts = do
putStrLn "Please enter the dividend :"
x <- readLn
putStrLn " Please enter the divisor :"
y <- readLn
return (x,y)
Now the processing. If I were doing more with this kind of data, or more frequently, I'd be using a record type to store the dividend, divisor, quotient and remainder, so bear that in mind for the future, but it's an overkill here.
I'm hackishly returning a list rather than a tuple, so I can use map to show them all:
sums :: (Int, Int) -> [Int]
sums (x,y) = [x, y, q, r, y * q, y * q + r] where
q = x `div` y
r = x `mod` y
The final piece of the jigsaw is the output. Again I prefer to generate this outside IO and then I can just mapM_ putStrLn on it later to print each line. I'd prefer this to take the record type, but I'm tolerating a list of strings as input instead since I'm assuming I've already shown them all.
explain :: [String] -> [String]
explain [x,y,q,r,yq,yq_r] =
[ concat ["Result: ", x, " / ", y, " = ", q, " remainder ", r]
, concat ["Proof: (", y, " x ", q, ") + ", r, " = ", yq, " + ", r, " = ", yq_r]
, "Is this what you had? "]
Now we can write main as
main = do (x,y) <- getInts
let ns = map show ( sums (x,y) )
es = explain ns
mapM_ putStrLn es
or even more succinctly, by piping together the functions explain . map show . sums, and applying that to the output of getInts using fmap:
main :: IO ()
main = fmap (explain . map show . sums) getInts
>>= mapM_ putStrLn
You might notice that I added a +r in the proof to make = always mean =, which is the correct mathematical usage, and mirror's Haskell's meaning for =.

Resources