DRY 原則を適用する特定の方法が Haskell の良い実践と見なされるかどうかについて質問があります。例を示してから、私が取っているアプローチが良い Haskell スタイルと見なされるかどうかを尋ねます。簡単に言えば、質問は次のとおりです。長い数式があり、その数式の小さなサブセットを別の場所で繰り返す必要がある場合、DRY を維持できるように数式の繰り返しサブセットを常に変数に入れますか? ? なぜですか、そうでないのですか?
例: 数字の文字列を取得し、その文字列を対応する 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" 式の小さな部分が必要であることがわかりました。たとえば、私のマシンでは、入力が (2^31 - 1) より大きい場合に Int オーバーフローが発生するため、処理できる最大値は 2,147,483,647 です。したがって、私は2つのチェックを入れました:
- 位の値が 9 (10 億の位) で、桁の値が > 2 の場合、エラーがあります。
- sum + (10 ^ place) * (digitToInt char) > maxInt の場合、エラーが発生します。
これらの 2 つのチェックにより、式の一部を繰り返す必要が生じたため、次の新しい変数を導入しました。
- digitValue = digitToInt char
- newPlaceComponent = (10^place) * digitValue
これらの変数を導入した理由は、単に DRY 原則を自動的に適用するためです。数式のこれらの部分を繰り返すことに気付いたので、それらを 1 回だけ定義しました。
しかし、これは良い Haskell スタイルと見なされるのでしょうか。明らかな利点がありますが、欠点も見られます。コードは間違いなく長くなりますが、私が見た Haskell コードの多くはかなり簡潔です。
では、あなたはこの Haskell スタイルが良いと考えていますか? また、この慣行に従っていますか? なぜ/なぜではないのですか?
価値があるのは、多くのエッジケースを処理するため、非常に大きな where ブロックを持つ私の最終的なソリューションです。DRY 原則を適用した結果、ブロックがどれだけ大きくなったかがわかります。
ありがとう。
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"