All the Haskell golf tips I know of:
Here's some advice that is often useful on code.golf specifically.
Program layout
Handling arguments
import System.Environment
main=getArgs>>=mapM(putStrLn.f).tail -- Apply `putStrLn.f` to each arg but the first
main=do _:a<-getArgs;mapM putStrLn[f x a|x<-a] -- Also useful sometimes, if you need `a`.
Printing a bunch of numbers line by line
main=mapM print[n|n<-[1..100],some condition on n]
Iterating and halting
Write a recursive function without an "otherwise" guard to halt when a condition becomes false.
-- Count down from 5 to 1:
main=f 5
f x|x>0=print x>>f(x-1)
This prints 5
4
3
2
1
and then crashes with Non-exhaustive patterns in function f
.
Miscellaneous advice
<>
Try It Online and anagol don't export <>
in Prelude yet, but code.golf does, and it is often useful.
See this post for some <>
tricks. putStr<>print
and id<>reverse
are nice.
Integer
vs. Int
Haskell math operators have generic types like (^) :: (Num a, Integral b) => a -> b -> a
, which means that the types of literal arguments may be inferred in surprising ways depending on the context of the result.
Usually Haskell prefers to infer Integer
(arbitrary-precision) as a concrete type for integer literals. But when some expression fills an Int
-typed parameter, type inference propagates Int
, a signed 64-bit integer type:
main=print $ 2^64+4 -- prints 18446744073709551620
main=print $ ['a'..]!!(2^64+4) -- prints 'e', because (!!) :: [a] -> Int -> a
-- so (2^64+4) must be an Int
Watch out for Int
-typed parameters in !!
, take
, drop
, and fromEnum
/toEnum
.
Compression
This kind of pattern is useful:
g '@'="Haskell"
g '#'="golf"
g c=[c]
main = putStrLn ("Tips for @ #ing, that is, code # in @.">>=g)
Also, mapM
is often useful. See this answer for a nice example.