Does the Pointfree version not compile, but does the dot version?

I want to write a Haskell function that returns a list added to the count time itself (e.g. lst * count in Python).

My first attempt:

 self_append_n :: Int -> [a] -> [a] self_append_n = concat . replicate 

My reasoning is that replicate takes a count value and a value and produces a list of values. When the value itself is a list, it remains only to combine the lists together. However, this is puzzling:

 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 the exact version:

 self_append_n ab = concat $ replicate ab 

and it works!

Why doesn't the dot-free version compile, but adding dots makes it work?

+6
source share
1 answer

This probably helps explicitly bracket the signatures:

 selfAppend :: Int -> ([a] -> [a]) replicate :: Int -> ([a]->[[a]]) concat :: [[a]] -> [a] 

If you try to make concat . replicate concat . replicate , you will get concat partially appied result of replicate , i.e. [a] -> [[a]] . This is not combined with [[a]] .

You need to pass both arguments to replicate first before passing the result. IMO the best way to do this is β€œhalf-tone”:

 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 just write

 selfAppend''' = concat .: replicate 
+11
source

Source: https://habr.com/ru/post/974622/


All Articles