Привет, я пытаюсь суммировать список кортежей в кортеж с помощью функции foldl, я пробовал использовать его с использованием в качестве параметра лямбда-выражения, но он выдает неправильное значение здесь, код:

data Point = Point {x,y :: Float}
sumPoint :: [Point] -> (Float,Float)
sumPoint xs = foldl (\(a,b) x-> (0+a,0+b)) (0.0,0.0) xs

Должно выйти sumPoint [Point 2 4, Point 1 2, Point (-1) (-2)] = (2.0,4.0) Но я получаю (0.0,0.0) Какой в ​​этом смысл?

1
Kevin 14 Ноя 2019 в 11:20
5
Вы полностью игнорируете x, а 0+a то же самое, что a, так что вы можете видеть, что здесь определенно не происходит суммирования. Попробуйте изменить лямбду на то, что добавляет два кортежа.
 – 
amalloy
14 Ноя 2019 в 11:32
1
О, понятно, так должно быть что-то вроде этого? sumPoint xs = foldl (\(a,b) (x,y)-> (x+a,y+b)) (0.0,0.0) xs но я получаю странную ошибку, она ожидает [(Float, Float)] фактического типа [Point], но Point - это (Float, Float)
 – 
Kevin
14 Ноя 2019 в 11:38
2
Закрывать. Попробуйте (\(a,b) (Point x y)-> (x+a,y+b)) , поскольку второй аргумент - точка, а не пара.
 – 
chi
14 Ноя 2019 в 12:00
Я подумал, спасибо за подсказку, потому что точка определяется как пара, которой должен соответствовать шаблон.
 – 
Kevin
14 Ноя 2019 в 12:06
Haskell использует номинальную типизацию (как и большинство языков программирования), где даже если два типа определены одинаково, но имеют разные имена, они считаются отдельными типами. Здесь Point и (Float,Float) структурно идентичны, но имеют разные имена, поэтому автоматическое преобразование отсутствует.
 – 
chi
14 Ноя 2019 в 12:11

2 ответа

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

data Point = Point {x,y :: Float} deriving Show

toTuple :: Point -> (Float, Float)
toTuple p = (x p, y p)

addPts :: Point -> Point -> Point
addPts p q = Point (x p + x q) (y p + y q)

sumPts :: [Point] -> Point
sumPts = foldl addPts (Point 0 0)

Итак, вам нужна функция toTuple . sumPts.

*Main> :t toTuple . sumPts
toTuple . sumPts :: [Point] -> (Float, Float)
3
Redu 14 Ноя 2019 в 12:12

Я изменил это на

sumPoint xs = foldl (\(a,b) (Point x y)-> (x+a,y+b)) (0.0,0.0) xs

Проблема заключалась в том, что я игнорировал x, а при 0 + a ничего не происходит.

2
Kevin 14 Ноя 2019 в 12:06