haskell - 将 `(->) ((->) a b)` 实现为应用仿函数的最佳方法是什么?

标签 haskell applicative

我正在处理问题 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/

相关文章:

scala - 何时以及为什么应该在 Scala 中使用 Applicative Functors

haskell - 单声道,组成和计算顺序

haskell - boolean 元组可以在守卫中进行匹配,就像模式匹配一​​样吗?

haskell - 是否有更可维护的方法来处理我的数据类型?

haskell - 范畴论 POV 中的 Applicative Functor 定义是什么?

haskell - Const Monoid 的应用实现

c++ - 任何开源项目都使用 FC++ 吗?

haskell - 在 Haskell 中定义自定义运算符的关联性

scala - 如何将值元组与函数元组结合起来?

haskell - 为什么 ZipList 不是 List 的默认应用实例