I want to write a Haskell function that returns a list appended to itself count times (like lst * count
in Python).
My first attempt is:
self_append_n :: Int -> [a] -> [a]
self_append_n = concat . replicate
My reasoning is that replicate
accepts a count and a value, and produces a list of values. When the value is itself a list, all that remains is to concatenate the lists together. However, this gives a bewildering error:
Couldn't match type `[a0]' with `[a] -> [a]'
Expected type: [[a0]] -> [a] -> [a]
Actual type: [[a0]] -> [a0]
In the first argument of `(.)', namely `concat'
In the expression: concat . replicate
In an equation for `self_append_n':
self_append_n = concat . replicate
Then I wrote a pointful version:
self_append_n a b = concat $ replicate a b
and it works!
Why does the point-free version fail to compile, but adding points makes it work?
It probably helps to explicitly parenthesise the signatures:
selfAppend :: Int -> ([a] -> [a])
replicate :: Int -> ([a]->[[a]])
concat :: [[a]] -> [a]
If you try to compose concat . replicate
, you end up giving concat
the partially appied result of replicate
, i.e. [a] -> [[a]]
. That doesn't unify with [[a]]
.
What you need to do is first pass both arguments to replicate
before handing on the result. IMO best way to do that is "semi-pointfree":
selfAppend n = concat . replicate n
Less readable alternatives would be
selfAppend' = curry $ concat . uncurry replicate
selfAppend'' = (concat.) . replicate
Or with the infamous operator
(.:) :: (c->d) -> (a->b->c) -> a->b->d
(.:) = (.).(.)
-- `≡ fmap fmap fmap`, also a popular implementation...
you can simply write
selfAppend''' = concat .: replicate
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With