2010-03-01 18 views
8

¿Hay alguna manera de usar el "mapa" de Haskell o algo similar con múltiples argumentos?Mapa aplicado a múltiples argumentos en Haskell

es decir, para encontrar la distancia entre un punto dado (que se define como una tupla) y una lista de otros puntos:

map distance (-3,-3) buildings 

Claramente, que no funciona, ya que intenta mapear "distancia" a (-3, -3), donde la distancia espera dos tuplas:

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

distancia toma dos puntos como argumentos: uno es (-3, -3) en este ejemplo, y uno se selecciona del edificios lista" ".

(-3, -3) es solo un ejemplo. Esto tendrá que ser una variable; no se puede codificar en la función.

Tal vez esto hará un poco más de sentido:

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. 

Respuesta

10

desea:

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

cuales es

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

distancia toma dos puntos como argumentos: uno es (-3, -3) en este ejemplo, y uno se selecciona de la lista " edificios ". (-3, -3) es solo un ejemplo. Esto tendrá que ser una variable; no se puede codificar en la función. –

+2

obviamente "edificios de mapa (primer punto de distancia)" funcionarían, ¿no? O para decirlo sin rodeos: "frombuilding point buildings = edificios de mapa (punto de distancia)" – ondra

+0

Por supuesto que puede reemplazar (-3, -3) con una variable. – 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

Niza deducción del formulario sin puntos –

2

Después de ver el comentario sobre la respuesta del ja I Supongo que deseas usar zipWith

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

Los documentation estados:

zipWith generaliza postal comprimiendo con la función dada como primer argumento, en lugar de una función tupling. Por ejemplo, zipWith (+) se aplica a dos listas para producir la lista de sumas correspondientes.

Así que en su código por encima de esto podría ser:

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 es la función que ha descrito, mientras que func2 es similar, pero toma en múltiples puntos de inicio en lugar de uno y encuentra el distancia entre cada combinación con los puntos finales.

0

La fórmula de la distancia es sencillo:

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

Nota el uso de coincidencia de patrones para descomponer los argumentos en lugar de ensuciando el código con fst y snd.

Las respectivas distancias de un punto a todos los puntos en una lista dada a continuación es

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

Aunque los argumentos parecen faltar, esto se conoce en la jerga como Haskell partial application.En distanceFrom, tenemos dos de ellos:

  1. distance p es una función de un punto cuyo valor es la distancia a ese punto de p
  2. map (distance p) es una función de una lista de puntos cuyo valor sea respectivas distancias esos puntos de p

Intente diseñar sus funciones Haskell para aplicaciones parciales para que sea más fácil combinar funciones pequeñas en funciones más grandes. Como se indica en ephemient's answer, puede llevar esto un paso más allá para obtener la definición pointfree (sin argumentos explícitos): un estilo más elegante y avanzado.

La distancia a cada punto en buildings desde todos los puntos en lPoints es entonces

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

Por ejemplo, haciendo lPoints y buildings iguales, la salida es

 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

Pero que es un poco aburrido en este caso particular dada toda la redundancia. Para imprimir el lugar strict upper triangle, utilice

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 

de salida:

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

No lo entiendo. ¿De qué sirve imprimir cosas así? Solo es redundante si lPpoints y los edificios son iguales. –

+0

@trinithis El "en este caso" que estaba en mi cabeza no lo hizo acceda a mi respuesta. ¡Gracias y editado! –