У меня есть вопрос о том, считается ли конкретный способ применения принципа DRY хорошей практикой в Haskell. Я собираюсь представить пример, а затем спросить, считается ли подход, который я использую, хорошим Стиль Хаскеля. В двух словах, вопрос заключается в следующем: если у вас длинная формула, а затем вам нужно повторить некоторые небольшие подмножества этой формулы в другом месте, всегда ли вы помещаете это повторное подмножество формулы в переменную, чтобы вы может остаться сухим? Почему или почему нет?
Пример:
Представьте, что мы берем строку цифр и преобразуем эту строку в соответствующее значение Int. (Кстати, это упражнение из "Real World Haskell").
Вот решение, которое работает, за исключением того, что оно игнорирует крайние случаи:
asInt_fold string = fst (foldr helper (0,0) string)
where
helper char (sum,place) = (newValue, newPlace)
where
newValue = (10 ^ place) * (digitToInt char) + sum
newPlace = place + 1
Он использует foldr, и аккумулятор является кортежем следующего значения места и суммы на данный момент.
Пока все хорошо. Теперь, когда я приступил к реализации проверок краевого регистра, я обнаружил, что мне нужны маленькие порции формулы "newValue" в разных местах для проверки на наличие ошибок. Например, на моей машине было бы переполнение Int, если бы входное значение было больше (2 ^ 31 - 1), поэтому максимальное значение, которое я мог бы обработать, составляет 2 147 483 647. Поэтому я поставил 2 чека:
- Если значение места 9 (место в миллиардах) и значение цифры> 2, возникает ошибка.
- Если сумма + (10 ^ место) * (digitToInt char)> maxInt, возникает ошибка.
Эти две проверки заставили меня повторить часть формулы, поэтому я ввел следующие новые переменные:
- digitValue = digitToInt char
- newPlaceComponent = (10 ^ место) * digitValue
Причина, по которой я ввел эти переменные, заключается просто в автоматическом применении принципа СУХОЙ: Я обнаружил, что повторяю эти части формулы, поэтому я определил их один раз и только один раз.
Однако мне интересно, считается ли это хорошим стилем Хаскеля. Есть очевидные преимущества, но я вижу и недостатки. Это определенно удлиняет код, тогда как большая часть кода на Haskell, который я видел, довольно лаконична.
Итак, вы считаете это хорошим стилем Хаскелла, и придерживаетесь ли вы этой практики или нет? Почему / почему нет?
И что бы это ни стоило, вот мое окончательное решение, которое имеет дело с рядом крайних случаев и, следовательно, имеет довольно большой блок where. Вы можете увидеть, насколько большим стал блок из-за моего применения принципа СУХОЙ.
Спасибо.
asInt_fold "" = error "You can't be giving me an empty string now"
asInt_fold "-" = error "I need a little more than just a dash"
asInt_fold string | isInfixOf "." string = error "I can't handle decimal points"
asInt_fold ('-':xs) = -1 * (asInt_fold xs)
asInt_fold string = fst (foldr helper (0,0) string)
where
helper char (sum,place) | place == 9 && digitValue > 2 = throwMaxIntError
| maxInt - sum < newPlaceComponent = throwMaxIntError
| otherwise = (newValue, newPlace)
where
digitValue = (digitToInt char)
placeMultiplier = (10 ^ place)
newPlaceComponent = placeMultiplier * digitValue
newValue = newPlaceComponent + sum
newPlace = place + 1
maxInt = 2147483647
throwMaxIntError =
error "The value is larger than max, which is 2147483647"