2014-08-28 23 views
8

Diyelim ki bir kayıt listesi var ve bunu medyanı alarak özetlemek istiyorum. Daha somut olarak, ben ölçümlerin bir listesi var ve ben bir medyan Location içine özetlemek istiyorum, bu yüzden bir şey gibiHaskell kayıtlarının bir listesini özetleyin

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

olduğunu varsayalım: gayet

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

ama ne olursa Ben CampusLocation s listesi var ve ben ortanca herkese yinelemeli uygulanan bir özetini CampusLocation, istediğiniz

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

gibi daha fazla iç içe şey var alanlar.

Bunu Haskell'de yapmanın en temiz yolu nedir? Lensler? Uniplate?

Düzenleme: Bonus: yerine biz özetlemek istediğiniz alanları içeren bir kaydın olmadığını, bunun yerine örtük bir liste vardı ne

? Örneğin:

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

nasıl buildings her aynı uzunlukta olduğunu varsayarak, bir ComplexCampus içine [ComplexCampus] özetleyebiliriz?

+0

I istersek aniden bu tür bir şeyi hayal eden bir "iki" mercek geçişi sığacak: "forall f" ile "applicals". Traversable f => (f a -> b) -> (f s -> t) '. Henüz kimsenin düşünmediği bir şey yok. –

+0

@ ØrjanJohansen Bu konuyla ilgili olup olmadığından emin değilim, ancak [dağıtıcı] 'da bir "kotraverse" var (http://hackage.haskell.org/package/distributive-0.4.4/docs/Data-Distributive. html). –

+0

@ AndrásKovács Uygun görünüyor ve bunu hatırlamam gerekirdi. Kmett'in olağan adlandırma şemasının önerdiği gibi ('Functor', onun yeterli olduğunu söyleyenler hariç) o zaman bir "kotraversal" olurdu. Soruyu aslında 'dağıtma' türünde yapmak için, 'Çifte'yi bir tür parametresine dönüştürmeleri gerekir. –

cevap

4

Burada, ComplexCampus'un tek bir ComplexCampus listesini özetlemek için Lenses w/Uniplate (belirtildiği gibi) kullanan bir summarize :: [ComplexCampus] -> ComplexCampus uygulaması vardır. Burada biplate kullanma

{-# 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 

olasılıkla overkill, ama ne olursa olsun averageLoc hepimiz x alanlar ve tüm y alan almak için yerlerin listesinde biplate kullanın. ComplexCampus'u tek bir Location içine özetlemek isterseniz, x değerlerinin tümünü ve değerlerini ComplexBuilding en üst düzeyinden ayıklamak için biplate kullanabilirsiniz. Örneğin

:

campusLocs' ^.. biplate . x tüm x değerleri bize verdiği ve campusLocs' ^.. biplate . y tıpkı bizim olabilir, y tüm konumları almak için Keza

değerleri hepimizi verir:

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

Ya Her Double: (campusLocs' ^.. biplate) ::[Double]

+0

Neden sadece 'summarize = ComplexCampus. map averageLoc. aktar. harita _buildings'? Ben burada mercek/önlük için temel kullanım görmüyorum. –

+4

'toplam xs/genericLength xs' xs'yi iki kez geçirir ve O (n) boşluğunu alır. Toplamı biriktiren katı bir kat kullanmak istersiniz ve bu sayede sabit alan içinde bir kez geçiş yapabilirsiniz. Daha fazla bilgi için http://www.haskellforall.com/2013/08/composable-streaming-folds.html –

+0

@ReinHenrichs Anyway'e bakın, asıl soru ortalamayı değil, ortalama olarak medyanı sorar. sabit alan. –