Общее расстояние с использованием Foldl - PullRequest
1 голос
/ 29 октября 2019

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

То, что я до сих пор делал, было так:

distancia :: [(Float,Float)] -> Float
distancia [] = 0.0
distancia [(_,_)] = 0.0
distancia (x:y:xs) = foldl(\(xa,ya)(xb,yb) -> sqrt(((xa-xb)**2)+((ya-yb)**2))) 0 xs

, поэтому ожидаемые результаты:

ghci> distancia [(0,0), (0,0), (1,0), (1,10)]
11.0
ghci> distancia [(1,1), (3,4)]
3.6055512

но я получаю следующую ошибку:

t3_fc42035.hs:9:22: error:
    * Couldn't match expected type `Float'
                  with actual type `(Float, Float)'
    * In the expression:
        foldl
          (\ (xa, ya) (xb, yb) -> sqrt (((xa - xb) ** 2) + ((ya - yb) ** 2)))
          0
          xs
      In an equation for `distancia':
          distancia (x : y : xs)
            = foldl
                (\ (xa, ya) (xb, yb) -> sqrt (((xa - xb) ** 2) + ((ya - yb) ** 2)))
                0
                xs
  |
9 | distancia (x:y:xs) = foldl(\(xa,ya)(xb,yb) -> sqrt(((xa-xb)**2)+((ya- yb)**2))) 0 xs
  |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

t3_fc42035.hs:9:47: error:
    * Couldn't match expected type `(Float, Float)'
                  with actual type `Float'
    * In the expression: sqrt (((xa - xb) ** 2) + ((ya - yb) ** 2))
      In the first argument of `foldl', namely
        `(\ (xa, ya) (xb, yb)
            -> sqrt (((xa - xb) ** 2) + ((ya - yb) ** 2)))'
      In the expression:
        foldl
          (\ (xa, ya) (xb, yb) -> sqrt (((xa - xb) ** 2) + ((ya - yb) ** 2)))
      0
      xs
  |
9 | distancia (x:y:xs) = foldl(\(xa,ya)(xb,yb) -> sqrt(((xa-xb)**2)+((ya-yb)**2))) 0 xs
  |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Я не понимаю, почему я должен соответствовать типу (Float, Float)

Ответы [ 2 ]

5 голосов
/ 29 октября 2019

Складывание, даже если это кажется разумным подходом, не является подходящим инструментом для этого конкретного случая, так как для вычисления значения аккумулятора вам нужно сразу два элемента из списка вместе с самим аккумулятором. Это невозможно, поэтому нет складывания.

Можно сделать как;

Prelude> :{
Prelude| let dist = sum . (zipWith hypot <*> tail)
Prelude|            where hypot = \(a,b) (c,d) -> sqrt((a-c)^2 + (b-d)^2)
Prelude| :}
Prelude> dist [(0,0), (0,0), (1,0), (1,10)]
11.0
Prelude> dist [(1,1), (3,4)]
3.605551275463989
0 голосов
/ 31 октября 2019

Так что я пытался придумать способ использования foldl, потому что для этой функции мне действительно нужно использовать foldl или foldr. Но я не могу заставить все примеры работать

distancia :: [(Float,Float)] -> Float
distancia [] = 0.0
distancia [(_,_)] = 0.0
distancia (x:y:xs) = foldl(\acc -> acc + (hypo x y)) 0 (y:xs)
 where
  hypo (xa,ya)(xb,yb) =  sqrt (((xa-xb)**2)+((ya-yb)**2))

Я получаю неправильный ввод, когда список начинается с [(0,0), (0,0)], он всегда дает мненеверный ввод, но если список начинается с [(0,0), (1,0), (0,0)], он работает.

*Main> distancia [(0,0), (0,0), (1,0), (1,10)]
0,0

но если я сделаю это

*Main> distancia [(0,0), (1,0), (0,0), (1,10)]
3,0

но при использовании этого примера это работает

*Main> distancia [(0,0), (1,1), (0,0), (-1, -1), (0,0)]
5.656854

*Main> distancia [(1,1), (0,0)]
1.4142135

Что не так?

...