10
\$\begingroup\$

Write a function Int -> Char -> Char -> [String] that will create the appropriate pattern.

For example: mapM_ putStrLn (pattern 48 '.' '+')

................................................
.+..+..+..+..+..+..+..+..+..+..+..+..+..+..+..+.
+.++.++.++.++.++.++.++.++.++.++.++.++.++.++.++.+
................................................

This idea is inspired by Writing nested for loops to produce certain output (but more general).

I am pretty satisfied with my code to solve this problem:

pattern :: Int -> Char -> Char -> [String]
pattern len a b = map (take len . cycle) [[a], [a, b, a], [b, a, b], [a]]

main :: IO()
main = mapM_ putStrLn (pattern 48 '.' '+')
\$\endgroup\$

1 Answer 1

5
\$\begingroup\$

Seems fine. However, depending on the context and the rest of the program, you can relax pattern's type:

pattern :: Int -> a -> a -> [[a]]

Also, since every putStrLn is basically hPutStrLn stdout, you could first glue all lines together with unlines and then print them with a single action:

main = putStr (unlines (pattern 48 '.' '+'))
\$\endgroup\$
5
  • \$\begingroup\$ I see your suggestions but fail to understand the reasoning about them... why is a general type better? Why is a single action better? \$\endgroup\$
    – Caridorc
    Commented Nov 27, 2015 at 16:47
  • 1
    \$\begingroup\$ @Caridorc: The most important parts of the answer are its first two words: Your code is fine. There are just some stylistic choices/alternatives you can consider. However, about the single action: putStrLn is basically the same as puts in C. From a performance point of view, you try to avoid many I/O calls (I/O, not IO) although this isn't really measurable in this small program. \$\endgroup\$
    – Zeta
    Commented Nov 27, 2015 at 16:58
  • \$\begingroup\$ cool performance trick :) What about the general type? \$\endgroup\$
    – Caridorc
    Commented Nov 27, 2015 at 17:00
  • 1
    \$\begingroup\$ @Caridorc: You cannot use pattern 48 1 2 in your original program ^^. The consensus in Haskell is: if you can make a function more general (without loosing something), make it more general. For example, you could define head :: [Int] -> Maybe Int. But head :: [a] -> Maybe a is a lot more useful. \$\endgroup\$
    – Zeta
    Commented Nov 27, 2015 at 17:01
  • \$\begingroup\$ Yeah, I meant it to be a text pattern, but it is always nice to know when things could be more general. \$\endgroup\$
    – Caridorc
    Commented Nov 27, 2015 at 17:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.