我正在处理问题 19 中的 Ninety-Nine Haskell Problems ,我遇到了以下困难。问题要求“将列表向左旋转 N 个位置”。这可以很容易地以有针对性的方式实现,例如,
rotate :: [a] -> Int -> [a]
rotate xs n = drop n xs ++ take n xs
但是,为了我自己的启发和挑战,我想使用应用仿函数以无点的方式实现这一点。例如,可以通过使用
(->) [a]
这一事实来消除其中一个参数。是 Applicative
仿函数和实现 rotate
如下:rotate :: Int -> [a] -> [a]
rotate n = (++) <$> drop n <*> take n
理想情况下,应该能够消除这两个参数,并将其写为
rotate :: [a] -> Int -> [a]
rotate :: (++) <$> drop <*> take
但这会导致类型错误。 (我不确定究竟是如何推断类型的,但问题似乎来自推断
Applicative
仿函数是 (->) Int
而不是 (->) ((->) Int [a])
的事实。)解决此问题的一种方法是手动实现
(->) ((->) a b)
作为 Applicative
的一个实例,特别是,设置<*> f g x y = f x y (g x y)
但似乎应该有一种更干净的方法来内联执行此操作。解决这个问题的“正确”方法是什么?
最佳答案
在不使用 Applicative 实例的情况下,有一种“最佳”方式可以做到这一点。
import Data.Semigroup
rotate = drop <> take
我们可以明确类型
(<>)
实例化于{-# Language ScopedTypeVariables #-}
{-# Language TypeApplications #-}
rotate :: forall a. Int -> [a] -> [a]
rotate = (<>) @(Int -> [a] -> [a]) drop take
使用这些实例解决:
instance Semigroup b => Semigroup (a -> b)
instance Semigroup [a]
关于haskell - 将 `(->) ((->) a b)` 实现为应用仿函数的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57578855/