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.