将镜头传递给一个功能

时间:2017-10-16 09:08:15

标签: haskell lens

我想根据记录中的特定值执行排序。因此我考虑将镜头传递到lensSort函数,但我无法使它工作。

理想情况下我可以做这样的事情

lensSort :: HasLens a => Lens' a b -> a -> a -> -> Ordering
lensSort lens x y | x ^. lens > y ^. lens = GT
                    | x ^. lens < y ^. lens = LT
                    | otherwise = GT

并且可以用类似

的方式来调用它
data Rectangle = Rectangle { _height :: Int, _width :: Int }
makeLenses'' Rectangle

let foo = [Rectangle 1 2, Rectangle 2 1]
sortBy (lensSort height) foo

我没有让这个工作起来,并担心我可能会完全咆哮错误的树,我仍然是Haskell的新手。

2 个答案:

答案 0 :(得分:7)

除了拼写错误之外,您的代码实际上几乎可以正常工作 - 显然需要的唯一事情是b实际上是可比较的。以下作品:

{-# LANGUAGE TemplateHaskell, RankNTypes #-}
import Control.Lens
import Control.Lens.TH
import Data.List

data Rectangle = Rectangle { _height :: Int, _width :: Int }
  deriving (Show)
makeLenses ''Rectangle

lensSort :: Ord b => Lens' a b -> a -> a -> Ordering
lensSort lens x y | x ^. lens > y ^. lens = GT
                    | x ^. lens < y ^. lens = LT
                    | otherwise = GT

foo :: [Rectangle]
foo = [Rectangle 1 2, Rectangle 2 1]

main = print $ sortBy (lensSort height) foo
-- [Rectangle {_height = 1, _width = 2},Rectangle {_height = 2, _width = 1}]

请注意,实际镜头并不需要传递,因为无论如何你只能用它作为吸气剂(≅功能)。所以你可以做到

import Data.Ord (comparing)
main = print $ sortBy (comparing (^.height))

......没有任何额外的定义。

答案 1 :(得分:4)

您可以实施sortByLens - 或更确切地说sortByGetting功能。从您的定义开始

{-# LANGUAGE TemplateHaskell #-}
module Test where

import Control.Lens
import Data.Function (on)
import Data.List (compare, sortBy)

data Rectangle = Rectangle { _height :: Int, _width :: Int }
$(makeLenses ''Rectangle)

我们将开始在ghci中创建您想要的功能:

stack ghci test.hs --package lens

> import Control.Lens
> import Data.Function
> import Data.List
> :t sortBy
sortBy :: (a -> a -> Ordering) -> [a] -> [a]
> :t on
on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
> :t compare
compare :: Ord a => a -> a -> Ordering

将这些与您的方法结合起来

>:t sortBy (compare `on` (view height))
sortBy (compare `on` (view height)) :: [Rectangle] -> [Rectangle]

为了使这一点更加通用,我们执行以下操作

>:t \lens -> sortBy (compare `on` (view lens))
\lens -> sortBy (compare `on` (view lens)) :: Ord a => Getting a s a -> [s] -> [s]

所以我们可以定义

sortByGetting :: Ord a => Getting a s a -> [s] -> [s]
sortByGetting g = sortBy (compare `on` view g)