LINUX.ORG.RU

[haskell][нуб] Show

 ,


0

1
data Roots a = 
	NoRoots 
	| TwoRoots a a 
	| OneRoot a

instance Show (Roots Int) where
	show NoRoots = "No roots found"
	show (TwoRoots a b) = "Two roots "++show a ++ " "++show b
	show (OneRoot a) = "One root " ++ show a

quadratic a b c  
	| d==0 = OneRoot x1
	| d>=0 = TwoRoots x1 x2
	| otherwise = NoRoots
	where 
		d = b*b-4.0*a*c;
		sqD = sqrt d;
		a2 = 2.0*a;
		x1 = (-b+sqD)/a2;
		x2 = (-b-sqD)/a2

Очевидный код на Haskell - решение квадратных уравнений. Что не пробовал - не получается написать show для Roots. Там на Int не обращайте внимания - это временный вариант. Не менее идиотский и не работающий чем остальные. Вообще должно работать не только с Int.

Кто подскажет что подправить, спасибо.

★★★★★

Вот полный исправленный быдлокод

import List

data Roots a = 
	NoRoots 
	| TwoRoots a a 
	| OneRoot a

instance Show a => Show (Roots a) where
	show NoRoots = "No roots found"
	show (TwoRoots a b) = "Two roots "++show a ++ " "++show b
	show (OneRoot a) = "One root " ++ show a

quadratic a b c  
	| d==0 = OneRoot x1
	| d>=0 = TwoRoots x1 x2
	| otherwise = NoRoots
	where 
		d = b*b-4.0*a*c;
		sqD = sqrt d;
		a2 = 2.0*a;
		x1 = (-b+sqD)/a2;
		x2 = (-b-sqD)/a2

stringToNumList = map read . words

main = do
	putStrLn "Enter coeficients a b c:";
	s <- getLine;
	let coef = stringToNumList s
		in putStrLn $ show $ 
			quadratic (coef!!0)(coef!!1)(coef!!2);
	return 0;

Буду разбирать ту загадочную конструкцию и что она значит

instance Show a => Show (Roots a) where
vertexua ★★★★★
() автор топика
Ответ на: комментарий от vertexua

>Буду разбирать ту загадочную конструкцию и что она значит

instance Show a => Show (Roots a) where

Ну, это... Если некий тип a - инстанс класса Show, то и тип (Roots a) тоже инстанс класса Show.

Твой первый вариант тоже должент работать, если добавить

{-# LANGUAGE FlexibleInstances #-}

Waterlaz ★★★★★
()

И это... ЗАЧЕМ?! Или просто потренироваться?

Waterlaz ★★★★★
()

1) Нужны модули,

2) Нужны типы для функций quadratic, stringToNumList и main - говорят, что это вроде докуметации (явная запись «контракта»),

3) Show и Read это такие стандартные классы типов (+ вот) из prelude,

4) Есть смысл написать свой класс типов Solve чтобы от него производить (instance) функции решения solve :: Equation -> Roots для разных полей отдельно, где Equation и Roots это типы «Уравнение» и «Корни» над этими полями, а «Решить» имеет тип («Уравнение» «Поле») -> («Корни» «Поле»). Вот пример для квадратных уравнений над ℝ и ℂ:

{-# LANGUAGE FlexibleInstances #-}

module QuadraticEquation (
  Equation(..),
  Roots(..),
  solve
  ) where

import List
import Complex

-- |
-- Representation of the quadratic equation over the field F
--
data A f = A f deriving (Eq)
data B f = B f deriving (Eq)
data C f = C f deriving (Eq)
data Equation f = Equation (A f) (B f) (C f) deriving (Eq)

showTerm :: (Num f) => String -> String -> f -> String
showTerm s1 s2 f = case f of
                     0 -> ""
                     1 -> s1
                     _ -> " + (" ++ show f ++ ")" ++ s2

instance (Show f, Num f) => Show (A f) where
  show (A f) = showTerm "x^2" "*x^2" f

instance (Show f, Num f) => Show (B f) where
  show (B f) = showTerm " + x" "*x" f

instance (Show f, Num f) => Show (C f) where
  show (C f) = showTerm (" + " ++ (show f)) "" f

instance (Show f, Num f) => Show (Equation f) where
  show (Equation a b c) = show a ++ show b ++ show c ++ " = 0"

-- |
-- Roots of that quadratic equation
--
data Roots f = NoRoots
             | TwoRoots f f
             | OneRoot  f

instance Show a => Show (Roots a) where
   show NoRoots        = "No roots found"
   show (TwoRoots a b) = "Two roots: " ++ show a ++ ", " ++ show b
   show (OneRoot a)    = "One root: " ++ show a

-- |
-- The `Solve' type class
--
class Solve f where
  solve :: (Equation f) -> (Roots f)

-- generic `solve' operation
genericSolve :: (Floating a) => Equation a -> (a, a, a)
genericSolve (Equation (A a) (B b) (C c)) = (d, x1, x2)
                                          where 
                                            d   = b * b - 4 * a * c
                                            sqD = sqrt d
                                            a2  = 2 * a
                                            x1  = (-b + sqD) / a2
                                            x2  = (-b - sqD) / a2

-- |
-- Solve in ℝ
--
instance Solve Float where
  solve equation
    | d == 0    = OneRoot x1
    | d > 0     = TwoRoots x1 x2
    | otherwise = NoRoots
    where (d, x1, x2) = genericSolve equation

-- |
-- Solve in ℂ
--
instance Solve (Complex Float) where
  solve equation = TwoRoots x1 x2
                 where (_, x1, x2) = genericSolve equation

{- |
-- Tests
--

Equation (A 1) (B 0) (C 1) 
> x^2 + 1 = 0

Equation (A 1) (B 2) (C 3)
> x^2 + 2*x + 3 = 0

Equation (A 1) (B 2) (C 0) 
> x^2 + (2)*x = 0

Equation (A 1) (B 2) (C 0) :: Equation (Complex Float)
> x^2 + (2.0 :+ 0.0)*x = 0

solve (Equation (A 1) (B 2) (C 3) :: Equation Float)
> No roots found

solve (Equation (A 1) (B 2) (C 3) :: Equation (Complex Float))
> Two roots: (-1.0) :+ 1.4142135, (-1.0) :+ (-1.4142135)

-}

Ну а IO и калькулятор в main уже отдельно делать и в своём модуле.

quasimoto ★★★★
()

Во-первых, хорошей абстракцией для результата недетерминированного вычисления является список. Поэтому, полагаю, нет смысла делать data Roots a с кучей конструкторов. Можно обойтись type или newtype со списком, если хочется ввести новый тип данных.

Во-вторых, show используется обычно(!) для сериализации данных, чтобы их потом можно было прочесть с помощью read. И, как правило, синтаксически представляет собой рабочий кусок кода.

balodja ★★★
()
Ответ на: комментарий от balodja

писать столько кода... Зачем?

(defun gii (a b c)
  (let ((d (sqrt (- (* b b) (* 4 a c)))))
    (values (/ (+ (- b) d) 2 a)
            (/ (- (- b) d) 2 a))))

?

Он же еще и тормозит.

Я не думаю что он тормозит (иначе где-то что-то очень не так).

Там можно решить уравнение в действительных числах, а можно в комплексных, а можно дописать ещё один инстанс и решить в каких-нибудь топологических поверхностях :)

quasimoto ★★★★
()
Ответ на: комментарий от balodja

Во-первых, хорошей абстракцией для результата недетерминированного вычисления является список.

А что в решении квадратного уравнения недетерминизированного?

Можно обойтись type или newtype со списком, если хочется ввести новый тип данных.

Почему? Если есть поле f, то «квадратное уравнение» это тройка Equation f f f, а его решение - двойка Roots f f, решение имеет тип Equation f -> Roots f, классы типов сюда прикручиваются, по моему, очень естесвенно, ну и расширение на все возможные поля - тоже (тут же не числодробилку писать, а классы типов попробовать задача стоит, как я понял).

quasimoto ★★★★
()
Ответ на: комментарий от balodja

Хотя, ты прав, немного перебрал с абстрацией:

solve :: (Floating a) => (a, a, a) -> (a, a)
solve (a, b, c) = (x1, x2)
                where 
                  d   = b * b - 4 * a * c
                  sqD = sqrt d
                  a2  = 2 * a
                  x1  = (-b + sqD) / a2
                  x2  = (-b - sqD) / a2

solveInR e = solve (e :: (Float, Float, Float))
solveInC e = solve (e :: ((Complex Float), (Complex Float), (Complex Float)))

solveInR (1,2,3)
> (NaN,NaN)

solveInC (1,2,3)
> ((-1.0) :+ 1.4142135,(-1.0) :+ (-1.4142135))

А «топологические поверхности» пусть будут инстансом этих Floating или чего-нибудь ешё (только чтобы generic solve работал).

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

> А что в решении квадратного уравнения недетерминизированного?

Недетерминированно здесь то, что при взятых наобум a, b и c заранее не ясно, сколько будет корней, а вводить 3 новых конструктора ради этого — обрекать себя на тонны обвязочного и ненужного кода.

Почему? Если есть поле f, то «квадратное уравнение» это тройка Equation f f f, а его решение - двойка Roots f f, решение имеет тип Equation f -> Roots f, классы типов сюда прикручиваются, по моему, очень естесвенно, ну и расширение на все возможные поля - тоже.

Классы типов можно прикручивать куда угодно по первому желанию. Правильный вопрос не в том, можно или нет; правильный вопрос в том, надо ли.

balodja ★★★
()

Воистину. Так как мы используем show a, то a должно быть воплощением класса Show. Поэтому для реализации Show (Roots a) требуется Show a

Be-LucK
()
Ответ на: комментарий от cathode

5 баллов.

Всем: спасибо, посмотрю ваш код.

vertexua ★★★★★
() автор топика
Ответ на: комментарий от cathode

интересно посмотреть на такое обобщение при степени больше 4 :)

при степени больше 4 программа должна считать группу Галуа многочлена, определять её разрешимость, и в случае положительного ответа - считать корни. уравнение вида x^5 = 1, например, тебя же не смущает, правда?

jtootf ★★★★★
()
Ответ на: комментарий от jtootf

а на уравнения произвольной степени обобщать кто будет? :)

Эварист Галуа, вестимо :)

quasimoto ★★★★
()
Ответ на: комментарий от jtootf

>> при степени больше 4 программа должна считать группу Галуа многочлена, [...]

А за пивом она не должна бегать?

cathode
()
Ответ на: комментарий от cathode

А за пивом она не должна бегать?

и открывать жестянки с пивом, да. главное - чтобы без зазнайства

jtootf ★★★★★
()
Ответ на: комментарий от Waterlaz

Б#?%*, а я еще ТС в громоздкости обвинял. =(

а мне понравилось; если немного упростить instance Show и принять исправление - будет вполне себе приятный код, все бы так упражнения писали

jtootf ★★★★★
()

Вот полиморфная версия. Нужно условие на тип.

instance Show t => Show (Roots t) where show NoRoots = «No roots found» show (TwoRoots a b) = «Two roots »++(show a) ++ " «++(show b) show (OneRoot a) = „One root “ ++ show a

gzh
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.