brian
brian

Reputation: 47

how to make a function return two different data types without using Either?

as said in the title, for example i have this function that throws an error of course :

bhaskara a b c = 
    if discriminant >= 0 then (x1,x2) else str_disc
    where 
        discriminant = (b^2 - (4*a*c))
        str_disc = "the discriminant is less than zero"
        x1 = ((-b) - sqrt (b^2 - (4*a*c))) / (2*a)
        x2 = ((-b) - sqrt (b^2 - (4*a*c))) / (2*a)

i heard you could use custom data types so i thought doing something like this but i'm clearly doing something wrong here :

data Result = (Double, Double) | String
bhaskara :: Double -> Double -> Double -> Result
bhaskara a b c = 
    if discriminant >= 0 then (x1,x2) else str_disc
    where 
        discriminant = (b^2 - (4*a*c))
        str_disc = "the discriminant is less than zero"
        x1 = ((-b) - sqrt (b^2 - (4*a*c))) / (2*a)
        x2 = ((-b) - sqrt (b^2 - (4*a*c))) / (2*a)

could someone show how to approach this?

by the way i know i'm not including the case where the discriminant is equal to zero

Upvotes: 0

Views: 161

Answers (2)

Henri Menke
Henri Menke

Reputation: 10939

If you don't want to use an algebraic datatype (although I'd recommend it), you can also resort to the “built-in error reporting” of the Double datatype. There is a special value which indicates that the the result of a computation is not a number (short: NaN or nan). This is fully supported in Haskell:

nan :: Double
nan = (0/0)

bhaskara :: Double -> Double -> Double -> (Double, Double)
bhaskara a b c = 
    if discriminant >= 0.0 then (x1,x2) else (nan,nan)
    where 
        discriminant = (b^2 - (4*a*c))
        x1 = ((-b) - sqrt (b^2 - (4*a*c))) / (2*a)
        x2 = ((-b) - sqrt (b^2 - (4*a*c))) / (2*a)

However, in this case the burden of checking for NaN (using isNaN) goes to the caller whereas with an algebraic datatype such as Either you can just pattern-match.

Upvotes: 2

Zeta
Zeta

Reputation: 105886

data Result = (Double, Double) | String

That's not a valid usage of data. You need to specify data constructors:

data Result = Result (Double, Double) | Error String

However, you don't need a pair in Result:

data Result = Result Double Double | Error String

bhaskara :: Double -> Double -> Double -> Result
bhaskara a b c = 
    if discriminant >= 0 then Result x1 x2  else Error str_disc
    where 
        discriminant = (b^2 - (4*a*c))
        str_disc = "the discriminant is less than zero"
        x1 = ((-b) - sqrt (b^2 - (4*a*c))) / (2*a)
        x2 = ((-b) - sqrt (b^2 - (4*a*c))) / (2*a)

That being said, Result is more or less Either String (Double, Double) as we can provide an isomorphism. You probably want to reconsider using Either.

Upvotes: 10

Related Questions