2010-03-01 13 views
8

Esiste un modo per utilizzare la "mappa" di Haskell o qualcosa di simile con più argomenti?Mappa applicata a più argomenti in Haskell

cioè di trovare la distanza tra un determinato punto (definito come una tupla) e un elenco di altri punti:

map distance (-3,-3) buildings 

Chiaramente, che non funziona, perché cerca di mappare "distanza" per (-3, -3), in cui la distanza attende due tuple:

let distance pointA pointB = sqrt ((frst pointB - frst pointA) * (frst pointB - frst pointA) + (scnd pointB - scnd pointA) * (scnd pointB - scnd pointA)) 

distanza prende due punti come argomenti: uno è (-3, -3) in questo esempio, e uno è selezionato dall'elenco "edifici ".

(-3, -3) è solo un esempio. Questo dovrà essere una variabile; non può essere codificato nella funzione.

Forse questo renderà un po 'più senso:

buildings = [(3,-2),(2,1),(5,3),(4,3),(4,-1)] 

firstDiff pointA pointB = subtract (fst pointA) (fst pointB) 

secondDiff pointA pointB = subtract (snd pointA) (snd pointB) 

distance pointA pointB = sqrt ((firstDiff pointA pointB) * (firstDiff pointA pointB) +  (secondDiff pointA pointB) * (secondDiff pointA pointB)) 

--- What I need to happen here is a list "score" to be created by taking all distances from a point in a list lPoints to a point in list buildings. 

risposta

10

desideri:

map (distance (-3, -3)) buildings 

quali è

map f buildings 
    where f = distance (-3, -3) 
+0

distanza prende due punti come argomenti: uno è (-3, -3) in questo esempio, e uno è selezionato dalla lista " edifici". (-3, -3) è solo un esempio. Questo dovrà essere una variabile; non può essere codificato nella funzione. –

+2

ovviamente "gli edifici della mappa (distanza primo punto)" funzionerebbero, no? O per dirla senza mezzi termini: "dal punto di costruzione edifici = mappa (punto di distanza) edifici" – ondra

+0

Ovviamente è possibile sostituire (-3, -3) con una variabile. – helium

19
allDistances src dests = map (\point -> distance src point) dests 

allDistances src dests = map (distance src) dests 

allDistances src = map (distance src) 

allDistances = map . distance 
+2

Nizza deduzione della –

2

Dopo aver visto il commento sulla risposta di ja I Suppongo che tu voglia usare zipWith

Prelude>:type zipWith 
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] 

I documentation stati:

zipWith generalizza zip da zippare con la funzione data come primo argomento, invece di una funzione tupling. Ad esempio, zipWith (+) viene applicato a due elenchi per produrre l'elenco delle somme corrispondenti.

Quindi nel tuo codice di cui sopra potrebbe sembrare:

Prelude> let dist a b = sqrt ((fst b - fst a) * (fst b - fst a) + (snd b - snd a) * (snd b - snd a)) 
Prelude> let buildings = [(1.0,1.0), (3.0,3.0), (4.0,4.0)] 
Prelude> let points = [ (1.2, 2.23), (2.23, 34.23), (324.3, 34.3) ] 
Prelude> zipWith dist points buildings 
[1.2461540835707277,31.239491032985793,321.7299799521332] 
0
distance (x, y) (z, w) = sqrt $ (x - z)^2 + (y - w)^2 

func1 = map . distance 

func2 starts ends = starts >>= flip func1 ends 

func1 è la funzione che hai descritto, mentre func2 è simile, ma prende in più punti di inizio invece di uno solo e trova la distanza tra ogni combinazione con i punti finali.

0

La formula distanza è semplice:

distance :: Floating a => (a,a) -> (a,a) -> a 
distance (x1,y1) (x2,y2) = sqrt $ (x2 - x1)^2 + (y2 - y1)^2 

noti l'uso di pattern matching per decomporre gli argomenti piuttosto che sporcare il codice con fst e snd.

Le rispettive distanze da un dato punto a tutti i punti in una lista è poi

distanceFrom :: Floating a => (a,a) -> [(a,a)] -> [a] 
distanceFrom p = map (distance p) 

Sebbene argomenti risultano mancanti, questo è noto in gergo come Haskell partial application.In distanceFrom, abbiamo due:

  1. distance p è una funzione di un punto il cui valore è la distanza di tale punto dalla p
  2. map (distance p) è una funzione di una lista di punti il ​​cui valore è quei punti rispettive distanze da p

Provare a progettare le funzioni Haskell per l'applicazione parziale per semplificare la combinazione di piccole funzioni in più grandi. Come indicato in ephemient's answer, è possibile eseguire questo passaggio ulteriormente per ottenere la definizione pointfree (senza argomenti espliciti) - uno stile più elegante e avanzato.

la distanza da ciascun punto in buildings da tutti i punti nel lPoints è quindi

main :: IO() 
main = do 
    mapM_ (putStrLn . unwords . map (printf "%6.3f")) score 
    where 
    score = [ distanceFrom x buildings | x <- lPoints ] 

Ad esempio, facendo lPoints e buildings uguali, l'uscita è

 0.000 3.162 5.385 5.099 1.414 
3.162 0.000 3.606 2.828 2.828 
5.385 3.606 0.000 1.000 4.123 
5.099 2.828 1.000 0.000 4.000 
1.414 2.828 4.123 4.000 0.000

Ma che è un po noioso questo caso particolare dato tutta la ridondanza. Per stampare invece il strict upper triangle, utilizzare

strictUpperTriangle :: [[a]] -> [[a]] 
strictUpperTriangle [] = [] 
strictUpperTriangle xs = go (init xs) 
    where go (x:xs) = tail x : map tail (go xs) 
     go [] = [] 

printSUT :: PrintfArg a => [[a]] -> IO() 
printSUT sut = putStr (unlines $ map pad sut) 
    where n = length sut 
     pad xs = let k = n - length xs in 
       unwords $ take k blanks ++ map (printf "%*.3f" w) xs 
     blanks = repeat (take w $ repeat ' ') 
     w = 6 :: Int 

main :: IO() 
main = printSUT tri 
    where 
    score = [ distanceFrom x buildings | x <- lPoints ] 
    tri = strictUpperTriangle score 

uscita:

 3.162 5.385 5.099 1.414 
     3.606 2.828 2.828 
       1.000 4.123 
         4.000
+0

Non capisco, che senso ha stampare cose del genere? È ridondante solo se lPpoint ed edifici sono uguali –

+0

@trinithis Il "in questo caso" che era nella mia testa non fallo alla mia risposta. Grazie e modificato! –