jga*_*aeb 4 haskell applicative
我正在研究“ 九十九个Haskell问题”中的问题19 ,并且遇到了以下困难。问题要求“将列表向左旋转N个位置”。这很容易以明确的方式实现,例如
rotate :: [a] -> Int -> [a]
rotate xs n = drop n xs ++ take n xs
Run Code Online (Sandbox Code Playgroud)
但是,对于我自己的教育和挑战,我想使用应用函子以一种无意义的方式实现这一点。举例来说,一个可以消除一个通过事实的论据(->) [a]是Applicative仿函数并实现rotate如下:
rotate :: Int -> [a] -> [a]
rotate n = (++) <$> drop n <*> take n
Run Code Online (Sandbox Code Playgroud)
理想情况下,一个人应该能够消除这两个参数,并将其写为
rotate :: [a] -> Int -> [a]
rotate :: (++) <$> drop <*> take
Run Code Online (Sandbox Code Playgroud)
但这会导致类型错误。(我不确定确切如何推断类型,但问题似乎出在推断的Applicative仿函数(->) Int不是的事实(->) ((->) Int [a])。)
解决此问题的一种方法是将手动实现(->) ((->) a b)为Applicative,尤其是将set设置为
<*> f g x y = f x y (g x y)
Run Code Online (Sandbox Code Playgroud)
但似乎应该有一种更简洁的方法来内联。解决此问题的“正确”方法是什么?
Fro*_*rog 13
有一种不使用Applicative实例的“最佳”方法。
import Data.Semigroup
rotate = drop <> take
Run Code Online (Sandbox Code Playgroud)
我们可以明确地知道(<>)实例化的类型
{-# Language ScopedTypeVariables #-}
{-# Language TypeApplications #-}
rotate :: forall a. Int -> [a] -> [a]
rotate = (<>) @(Int -> [a] -> [a]) drop take
Run Code Online (Sandbox Code Playgroud)
使用以下实例解决:
instance Semigroup b => Semigroup (a -> b)
instance Semigroup [a]
Run Code Online (Sandbox Code Playgroud)
两种选择:
rotate = liftA2 (liftA2 (++)) drop take
rotate = getCompose (liftA2 (++) (Compose drop) (Compose take))
Run Code Online (Sandbox Code Playgroud)
后者成为内联实例方法定义为后前者Compose的Applicative实例。
您可以恢复使用拼写liftA2s的功能,当然(<$>),(<*>)如果愿意,可以使用。
| 归档时间: |
|
| 查看次数: |
163 次 |
| 最近记录: |