如何在不使用 Either 的情况下使函数 return 具有两种不同的数据类型?

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

如标​​题所述,例如我有这个函数当然会抛出错误:

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)

我听说你可以使用自定义数据类型,所以我想做这样的事情,但我在这里显然做错了什么:

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)

有人可以展示如何解决这个问题吗?

顺便说一下,我知道我不包括判别式等于零的情况

data Result = (Double, Double) | String

这不是 data 的有效用法。您需要指定数据构造函数:

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

但是,您不需要 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)

也就是说,Result 或多或少是 Either String (Double, Double),因为我们可以提供同构。您可能想重新考虑使用 Either.

如果您不想使用代数数据类型(尽管我推荐它),您也可以求助于 Double 数据类型的“built-in 错误报告”。有一个特殊值表示计算结果不是数字(简称:NaN 或 nan)。 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)

但是,在这种情况下,检查 NaN(使用 isNaN)的负担转给了调用者,而对于 Either 等代数数据类型,您只需 pattern-match.