как заставить функцию возвращать два разных типа данных без использования либо?

как сказано в заголовке, например, у меня есть эта функция, которая, конечно, выдает ошибку:

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)

может кто-нибудь показать, как подойти к этому?

кстати я знаю, что не включаю случай, когда дискриминант равен нулю


person brian    schedule 08.08.2020    source источник
comment
Вам нужно использовать конструктор данных, например data Result = Values Double Double | Error String   -  person Willem Van Onsem    schedule 08.08.2020
comment
Bhaskar — классное название функции, оно что-то значит?   -  person Evgeny    schedule 08.08.2020
comment
@Evgeny, ха-ха, да, я не знаю, что это значит, это просто формула этого парня en.wikipedia.org /wiki/Bh%C4%81skara_II позволяет находить корни уравнений второй степени   -  person brian    schedule 08.08.2020
comment
Круто, спасибо за ссылку! Я не знал, кто предложил это первым. Это была безымянная формула в нашей школьной программе. В целом хороший пример для Либо вы предложили.   -  person Evgeny    schedule 09.08.2020


Ответы (2)


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.

person Zeta    schedule 08.08.2020
comment
большое спасибо, у вас есть идеи, можно ли запретить отображение конструкторов данных рядом с результатом при печати? - person brian; 08.08.2020
comment
@brian Вы должны написать свой собственный экземпляр Show для Result. - person Henri Menke; 09.08.2020

Если вы не хотите использовать алгебраический тип данных (хотя я бы рекомендовал его), вы также можете прибегнуть к «встроенным отчетам об ошибках» типа данных Double. Существует специальное значение, указывающее, что результат вычисления не является числом (сокращенно: 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, вы можете просто сопоставить шаблон.

person Henri Menke    schedule 09.08.2020