I'm working on Problem 19 in Ninety-Nine Haskell Problems, and I've encountered the following difficulty. The problem asks to "rotate a list N places to the left." This could easily be achieved in a pointed way, e.g.,
rotate :: [a] -> Int -> [a]
rotate xs n = drop n xs ++ take n xs
However, for my own edification and for the challenge, I'd like to implement this in a point-free way using applicative functors. For instance, one can eliminate one of the arguments by using the fact that (->) [a]
is an Applicative
functor and implement rotate
as follows:
rotate :: Int -> [a] -> [a]
rotate n = (++) <$> drop n <*> take n
Ideally, one should be able to eliminate both arguments, and write it as
rotate :: [a] -> Int -> [a]
rotate :: (++) <$> drop <*> take
but this causes a type error. (I'm not sure exactly how the type are being inferred, but the problem seems to be coming from the fact that the inferred Applicative
functor is (->) Int
rather than (->) ((->) Int [a])
.)
One way to solve this would be to manually implement (->) ((->) a b)
as an instance of Applicative
, and, in particular, set
<*> f g x y = f x y (g x y)
but it seems that there should be a cleaner way to do this inline. What is the "right" way to solve this problem?
There's an "optimal" way of doing this without using the Applicative instance.
import Data.Semigroup
rotate = drop <> take
We can be explicit about the type (<>)
is instantiated at
{-# Language ScopedTypeVariables #-}
{-# Language TypeApplications #-}
rotate :: forall a. Int -> [a] -> [a]
rotate = (<>) @(Int -> [a] -> [a]) drop take
Resolved using these instances:
instance Semigroup b => Semigroup (a -> b)
instance Semigroup [a]
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