Карта относилась к нескольким аргументам в Haskell

Существует ли способ использовать "карту" Haskell или что-то похожее с несколькими аргументами?

т.е. найти расстояние между данной точкой (определенным как кортеж) и списком других точек:

map distance (-3,-3) buildings

Очевидно, это не работает, потому что это пытается отобразить "расстояние" до (-3,-3), где расстояние ожидает два кортежа:

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

расстояние берет две точки в качестве аргументов: каждый (-3,-3) в этом примере, и каждый выбран из списка "здания".

(-3,-3), просто пример. Это должно будет быть переменной; это не может быть hardcoded в функцию.

Возможно, это будет иметь немного больше смысла:

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.
9
задан Jason B 1 March 2010 в 22:29
поделиться

5 ответов

вы хотите:

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

то есть

map f buildings 
  where f = distance (-3, -3)  
13
ответ дан 4 December 2019 в 06:35
поделиться
allDistances src dests = map (\point -> distance src point) dests

allDistances src dests = map (distance src) dests

allDistances src = map (distance src)

allDistances = map . distance
21
ответ дан 4 December 2019 в 06:35
поделиться

После просмотра комментария к ответу ja Я предполагаю, что вы хотите использовать zipWith

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

В документации говорится:

zipWith обобщает zip путем архивирования с функцией, заданной в качестве первого аргумента, вместо функции кортежа. Например, zipWith (+) применяется к двум спискам для получения списка соответствующих сумм.

В приведенном выше коде это может выглядеть так:

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]
2
ответ дан 4 December 2019 в 06:35
поделиться

Формула расстояния проста:

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

Обратите внимание на использование сопоставления по образцу для разложения аргументов, а не на замусоривание кода fst и snd.

Соответствующие расстояния от заданной точки до всех точек в списке находятся тогда

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

Хотя аргументы кажутся отсутствующими, это известно на языке Haskell как частичное применение. В distanceFrom их два:

  1. distance p - функция одной точки, значение которой - расстояние этой точки от p
  2. map (distance p) - функция списка точек, значение которой - соответствующие расстояния этих точек от p

Старайтесь проектировать свои функции Haskell для частичного применения, чтобы было легко объединять маленькие функции в большие. Как отмечено в ответе ephemient'а, вы можете продвинуть это на шаг дальше, чтобы получить pointfree определение (без явных аргументов) - более элегантный, продвинутый стиль.

Тогда расстояние до каждой точки в зданиях от всех точек в lPoints будет

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

Например, если сделать lPoints и здания равными, то получится

 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

Но это немного скучно в данном конкретном случае, учитывая всю избыточность. Чтобы вместо этого вывести строгий верхний треугольник, используйте

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

Output:

 3.162  5.385  5.099  1.414
        3.606  2.828  2.828
               1.000  4.123
                      4.000
0
ответ дан 4 December 2019 в 06:35
поделиться
distance (x, y) (z, w) = sqrt $ (x - z) ^ 2 + (y - w) ^ 2

func1 = map . distance

func2 starts ends = starts >>= flip func1 ends

func1 - это функция, которую вы описали, а func2 похожа, но принимает несколько начальных точек вместо одной и находит расстояние между каждой комбинацией с конечными точками.

0
ответ дан 4 December 2019 в 06:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: