假设我有一个记录列表,我想通过取中位数来总结一下.更具体地说,我说
data Location = Location { x :: Double, y :: Double }
Run Code Online (Sandbox Code Playgroud)
我有一个测量列表,我想将它总结为中位数Location,所以类似于:
Location (median (map x measurements)) (median (map y measurements))
Run Code Online (Sandbox Code Playgroud)
这很好,但如果我有更多嵌套的东西,例如:
data CampusLocation = CampusLocation { firstBuilding :: Location
,secondBuilding :: Location }
Run Code Online (Sandbox Code Playgroud)
我有一个CampusLocations 列表,我想要一个摘要CampusLocation,其中中位数递归地应用于所有字段.
在Haskell中最干净的方法是什么?镜头?Uniplate中?
编辑:奖金:
如果不是包含我们想要汇总的字段的记录,我们有一个隐含的列表呢?例如:
data ComplexCampus = ComplexCampus { buildings :: [Location] }
Run Code Online (Sandbox Code Playgroud)
我们如何将a概括[ComplexCampus]为a ComplexCampus,假设每个buildings长度相同?
这是一个summarize :: [ComplexCampus] -> ComplexCampus使用Lenses w/Uniplate(如你所提到的)将一个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
Run Code Online (Sandbox Code Playgroud)
在这里使用biplate可能有点过分,但无论averageLoc我们biplate在位置列表中使用以获取所有x字段和所有y字段.如果您想将a汇总ComplexCampus为单个,Location我们可以使用从顶层biplate提取所有x值和所有y值ComplexBuilding.
例如:
campusLocs' ^.. biplate . x给出了所有x值并campusLocs' ^.. biplate . y给出了所有y值
同样,要获得所有位置,我们可以这样做:
(campusLocs' ^.. biplate) ::[Location]
或者,如果我们想要每一个Double:
(campusLocs' ^.. biplate) ::[Double]