3
\$\begingroup\$

I have written Haskell code to my spec to help me grasp types and syntax, because I am learning. I hope to generalize it further to accommodate more kinds of equations. I am (perhaps prematurely) worried that repeated usage of delta in multiple places is going to slow down my code, but I don't see how I can avoid it.

I am a bit confused about whether I should use Floating class or just use Float concrete type everywhere.

I appreciate any and all tips.

Here's the expected output

Equation -10.0x^2 +4.0x +1.0 = 0 has following 2 solutions:
0.28708285
-8.708288e-2

And the code

-- MathPrimer

delta :: Floating a => a -> a -> a -> a
x1 :: Floating a => a -> a -> a -> a
x2 :: Floating a => a -> a -> a -> a

delta a b c = b * b - 4 * a * c

x1 a b c = ( - b - sqrt(delta a b c)) / ( 4 * a * c )
x2 a b c = ( - b + sqrt(delta a b c)) / ( 4 * a * c )


class Algebraic equ where
    algebraicForm :: equ -> String

class (ZeroEquation equ) where
    solve :: equ -> [Float]
    solutionCount :: equ -> Int


data Equation = Quadratic {a :: Float, b :: Float, c :: Float}
    deriving (Show, Read, Eq)

instance (ZeroEquation Equation) where
    solve (Quadratic a b c) = solutions
        where
            both = [x1 a b c, x2 a b c]
            one = [x1 a b c]
            zero = []
            solutions = if _delta < 0 then zero else if _delta == 0 then one else both
            _delta = (delta a b c)
    solutionCount (Quadratic a b c) = count
        where
            count = if _delta < 0 then 0 else if _delta == 0 then 1 else 2
            _delta = (delta a b c)

instance (Algebraic Equation) where
    algebraicForm (Quadratic a b c) = show a ++ "x^2 +" ++ show b ++ "x +" ++ show c

showEquation :: Equation -> String
showEquation equ = "Equation " ++ description ++ " = 0 has following " ++ count ++ " solutions:\n" ++ solutions
    where
        count = show $ solutionCount equ
        description = algebraicForm equ
        solutions = unlines $ map show $ solve equ

main = do
    let equation = Quadratic (-10) 4 1
    putStrLn $ showEquation equation
\$\endgroup\$
4
  • \$\begingroup\$ Welcome to posting on Code Review (long time lurker, I see!). Just out of interest, since I don't do Haskell myself - does this find only the real roots, or will it find complex roots where they exist? \$\endgroup\$ Jan 12, 2021 at 21:35
  • \$\begingroup\$ only real, but I just have to substitute sqrt for a complex one to get complex. But I decided against it because it was no fun when there's only 2 or 0 solutions. I also would have to adjust Float and Floating to some complex types I don't know yet. \$\endgroup\$
    – loa_in_
    Jan 12, 2021 at 21:59
  • \$\begingroup\$ Also thank you very much! Code Review can be very helpful with learning I saw so I decided to try it myself @TobySpeight \$\endgroup\$
    – loa_in_
    Jan 12, 2021 at 22:03
  • 1
    \$\begingroup\$ No problem - I'm just taking the opportunity to learn something about Haskell. Micro-review: consider changing the word "solutions" to "solution" when b² = 4ac. How would you ensure that the message is translatable (remembering that different languages inflect by number very differently)? \$\endgroup\$ Jan 12, 2021 at 22:04

1 Answer 1

3
\$\begingroup\$

It's hard to tell if the compiler would be able to eliminate duplicate calls to delta. It may do that, by inlining the x1 and x2 functions and then eliminating common subexpressions. Personally though, I prefer to do this myself. The following modification is guaranteed to call delta only once:

solve (Quadratic a b c) = solutions
    where
        both = [x1, x2]
        one = [x1]
        zero = []
        solutions = if _delta < 0 then zero else if _delta == 0 then one else both
        _delta = (delta a b c)
        x1 = ( - b - sqrt _delta) / ( 4 * a * c )
        x2 = ( - b + sqrt _delta) / ( 4 * a * c )
\$\endgroup\$
1
  • \$\begingroup\$ That's a fair suggestion. I guess I'll have to resort to benchmarking. \$\endgroup\$
    – loa_in_
    Jan 13, 2021 at 23:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.