HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Print a sequence of n numbers

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
numbersprintsequence

Problem

I have a simple function that takes an Integer n and return a string representing the array from 1..n.

nthLine :: Integer -> String
nthLine n = intercalate " " $ map show [1..n]


The main function takes input n from the user and prints the nthLine out to screen:

getInteger :: String -> Integer      # This seems redundant
getInteger xs = (read xs)::Integer 

nthLineStr :: String  -> String      # And so does this function
nthLineStr xs = nthLine (getInteger xs )

main = do line <- fmap nthLineStr getLine
          putStrLn line


Any tips on how this may be simplified/made better?

Solution

You can use unwords in place of intercalate " ".

Given the type signature of getInteger :: String -> Integer the return type of read xs must be Integer in order for the type system to unify what you've written, making your type annotation on the function implementation there redundant. You can perform eta-reduction on getInteger then (that is, write it in pointfree style) and drop the xs for an implementation of—

getInteger :: String -> Integer
getInteger = read


This is now obviously a specialization of read, which isn't all that interesting. Look now to the implementation of nthLineStr where you can see that the result of getInteger xs is passed to nthLine. Because the type of nthLine is given as Integer -> String, the compiler can again determine that read must return an Integer if you change the definition of nthLineStr to—

nthLineStr :: String -> String
nthLineStr xs = nthLine (read xs)


You can perform eta-reduction again to write nthLineStr as nthLineStr = nthLine . read. nthLineStr is a bit of a kludge though, in that it muddies the waters between your pure code and the outside world. Keep your (de-)serialization functions apart from the rest of your program, it shouldn't matter to the core logic of your application whether you were passed a String or a Text value or length encoded sequence of unit values ([()]).

main :: IO ()
main = do n <- fmap read getLine
       putStrLn $ nthLine n


Or you could use another Prelude function, interact :: (String -> String) -> IO () (a useful concept, but note this changes the semantics a bit).

main :: IO ()
main = interact (nthLine . read)

Code Snippets

getInteger :: String -> Integer
getInteger = read
nthLineStr :: String -> String
nthLineStr xs = nthLine (read xs)
main :: IO ()
main = do n <- fmap read getLine
       putStrLn $ nthLine n
main :: IO ()
main = interact (nthLine . read)

Context

StackExchange Code Review Q#85737, answer score: 4

Revisions (0)

No revisions yet.