Другие ответы касаются того, что пошло не так в вашем подходе. С теоретической точки зрения, однако, у каждого из них есть свои недостатки: они либо дают вам [Int]
, а не Int
, либо используют (+)
при преобразовании обратно из [Int]
в Int
. Более того, они используют mod
и div
в качестве подпрограмм при определении сложения - это было бы хорошо, но тогда, чтобы быть теоретически обоснованным, вы хотели бы убедиться, что вы можете сами определять mod
и div
, не используя дополнение как подпрограмма!
Поскольку вы говорите, что эффективность не имеет значения, я предлагаю использовать обычное определение сложения, которое дают математики, а именно: 0 + y = y и (x + 1) + y = (x + y) +1. Здесь вы должны прочитать +1
как отдельную операцию, а не как сложение, более примитивное: то, которое просто увеличивает число. Мы пишем это succ
в Хаскеле (и его "обратное" - pred
). Имея в виду это теоретическое определение, Хаскелл почти пишет сам:
add :: Int -> Int -> Int
add 0 y = y
add x y = succ (add (pred x) y)
Итак: по сравнению с другими ответами мы можем взять Int
и вернуть Int
, и мы используем только те подпрограммы, которые «чувствуют» себя более примитивными: succ
, pred
и проверяют, число ноль или не равно нулю. (И мы получаем только три короткие строки кода ... около трети до самой короткой предложенной альтернативы.) Конечно, цена, которую мы платим, очень плохая производительность ... попробуйте add (2^32) 0
!
Как и другие ответы, это работает только для положительных чисел. Когда вы будете готовы к обработке отрицательных чисел, мы должны снова поболтать - есть несколько захватывающих математических трюков , которые нужно потянуть.