8

假设我有一个记录列表,我想通过取中位数来总结它。更具体地说,说我有

data Location = Location { x :: Double, y :: Double }

我有一个测量列表,我想把它总结成一个中位数Location,比如:

Location (median (map x measurements)) (median (map y measurements))

那很好,但是如果我有更多嵌套的东西怎么办,例如:

data CampusLocation = CampusLocation { firstBuilding :: Location
                                      ,secondBuilding :: Location }

我有一个CampusLocations 列表,我想要一个 summary CampusLocation,其中中位数递归地应用于所有字段。

在 Haskell 中最干净的方法是什么?镜头?单板?

编辑:奖金:

如果我们想要汇总的不是包含字段的记录,而是一个隐式列表,该怎么办?例如:

data ComplexCampus = ComplexCampus { buildings :: [Location] }

假设每个的长度相同,我们如何将 a 总结[ComplexCampus]为 a ?ComplexCampusbuildings

4

1 回答 1

5

这是一个实现,summarize :: [ComplexCampus] -> ComplexCampus它使用带有 Uniplate 的 Lenses(如您所提到的)来汇总 ComplexCampus 列表和单个 ComplexCampus。

{-# Language TemplateHaskell,DeriveDataTypeable #-}
import Control.Lens
import Data.Data.Lens
import Data.Typeable
import Data.Data
import Data.List(transpose,genericLength)
data Location = Location { _x :: Double, _y :: Double } deriving(Show,Typeable,Data)


data CampusLocation =  CampusLocation { _firstBuilding :: Location, _firsecondBuilding :: Location }deriving(Show,Typeable,Data)
data ComplexCampus = ComplexCampus { _buildings :: [Location] } deriving(Show,Typeable,Data)


makeLenses ''Location
makeLenses ''CampusLocation
makeLenses ''ComplexCampus

l1 = Location 1 10
l2 = Location 2 20
l3 = Location 3 30


c1 = CampusLocation l1 l2
c2 = CampusLocation l2 l3
c3 = CampusLocation l1 l3
campusLocs = [c1,c2,c3]


c1' = ComplexCampus [l1, l2]
c2' = ComplexCampus [l2, l3]
c3' = ComplexCampus [l1, l3]
campusLocs' = [c1',c2',c3']


average l = (sum l) / (genericLength l)

-- returns average location for a list of locations
averageLoc locs = Location {
             _x = average $ locs ^.. biplate . x,
             _y = average $ locs ^.. biplate . y
             }


summarize :: [ComplexCampus] -> ComplexCampus
summarize ccs = ComplexCampus $ ccs ^.. biplate . buildings ^.. folding transpose . to averageLoc

在这里使用 biplate 可能有点矫枉过正,但无论averageLoc我们biplate在位置列表上使用来获取所有x字段和所有y字段。如果您想将 a 汇总ComplexCampus为一个Location,我们可以使用它来从顶层biplate提取所有x值和所有值。yComplexBuilding

例如:

campusLocs' ^.. biplate . x给我们所有的 x 值并campusLocs' ^.. biplate . y给我们所有的 y 值

同样,要获取所有位置,我们可以这样做:

(campusLocs' ^.. biplate) ::[Location]

或者,如果我们想要每个 Double: (campusLocs' ^.. biplate) ::[Double]

于 2014-08-28T06:18:20.700 回答