# Haskell basic typeclass primer (quadratic equations)

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

• 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? Jan 12, 2021 at 21:35
• 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. Jan 12, 2021 at 21:59
• Also thank you very much! Code Review can be very helpful with learning I saw so I decided to try it myself @TobySpeight Jan 12, 2021 at 22:03
• 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)? Jan 12, 2021 at 22:04

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 )

• That's a fair suggestion. I guess I'll have to resort to benchmarking. Jan 13, 2021 at 23:29