2017-10-16 25 views
3

我想根據記錄中的特定值執行排序。因此,我正在考慮將鏡頭傳遞到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的新手。

回答

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}] 

注意這裏是不是真的需要繞過一個實際的鏡頭,因爲你只把它當作一個getter(≅function)反正。所以,你可以做

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

...沒有任何額外的定義。

+0

用'比較'做這件事很棒,謝謝 – eddiec

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) 
+1

你也可以使用['sortOn'](https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-List.html#v:sortOn):'sortOnGetting g = sortOn (view g)' – jpath

+0

@jpath thx - 出於某種原因,我總是忘記這個函數存在! – epsilonhalbe