Получение Data.Complex в Haskell

У меня есть код, который выглядит примерно так:

import Data.Complex

data Foo = N Number
         | C ComplexNum

data Number = Int Integer
            | Real Float
            | Rational Rational
     deriving Show

data ComplexNum = con1 (Complex Integer)
                | con2 (Complex Float)
                | con3 (Complex Rational)
     deriving Show

Но это кажется плохим способом сделать это. я бы предпочел

data Foo = N Number
         | C (Complex Number)

и создайте ComplexNumber с чем-то похожим на ComplexNumber $ Real 0.0.

Вопрос в том, как сделать Complex Number возможным. Поскольку все типы в Number имеют соответствующие экземпляры Complex, могу ли я просто добавить deriving Complex к Number?


person user3125280    schedule 26.01.2014    source источник
comment
Как вы предполагаете, что сможете добавить ComplexNum формы con2 (Complex Float) к форме con3 (Complex Rational)?   -  person Tom Ellis    schedule 26.01.2014
comment
@Tom, предоставляя эти функции самостоятельно (продвижение / преобразование типов и т. д.) — Number включает в себя все представления чисел, которые я хочу, такие как Int, Integer и т. д., и я буду использовать дробное число для числа, а затем предоставлю свой собственный сложный класс с instance Fractional A => Fractional (Complex a). Я надеялся, что кто-нибудь знает, как это сделать, используя Data.Complex вместо моего собственного.   -  person user3125280    schedule 26.01.2014
comment
@ user3125280 Почему? Что даст вам эта потеря знаний и контроля над шрифтом?   -  person not my job    schedule 26.01.2014
comment
@chunksOf50 ха-ха, это то, чего я ожидал от хаскеллера - он для реализации слабо типизированного языка (который я использую как возможность выучить хаскел). Все числовые представления должны быть совместимы с базовой арифметикой. (Я решил это сам, поэтому, если вы не знаете лучший способ, не беспокойтесь слишком сильно :))   -  person user3125280    schedule 26.01.2014
comment
@user3125280: user3125280: Итак, вы сами написали instance Complex Number со всеми этими преобразованиями типов, реализованными вручную. Вы не можете ожидать, что компилятор сделает это за вас!   -  person Tom Ellis    schedule 26.01.2014
comment
@TomEllis Ну, на самом деле я могу ожидать, что стандартный библиотечный сложный класс сможет быть производным от экземпляра дробного (куда я поместил преобразования типов) - в этом нет ничего неразумного. Разве это невозможно?   -  person user3125280    schedule 26.01.2014
comment
(Извините, я на самом деле имею в виду instance Num Number). В любом случае, довольно неясно, что вы пытаетесь сделать. Вы можете сформировать тип данных Complex Number. Хорошо. Это просто пары Number. У него не будет автоматического экземпляра Num, если вы не предоставите экземпляр RealFloat для Number (экземпляр, который вряд ли имеет смысл в любом случае).   -  person Tom Ellis    schedule 26.01.2014
comment
@TomEllis В точности моя точка зрения (хотя я использовал дробную часть вместо числа). Я думаю, совершенно ясно, что я пытаюсь сделать - сделать мой ComplexNumber зависимым от Number - и ответ: вы не можете, не создавая свой собственный ComplexClass   -  person user3125280    schedule 26.01.2014
comment
Но вы можете сделать data Foo = N Number | C (Complex Number). Я не знаю, что вы подразумеваете под ComplexClass, но я сомневаюсь, что вам это нужно. Вам действительно нужен экземпляр Num, но, поскольку у вас все равно есть все эти преобразования типов, которые нужно писать вручную, вряд ли это кажется дополнительной трудностью.   -  person Tom Ellis    schedule 26.01.2014
comment
давайте продолжим это обсуждение в чате   -  person user3125280    schedule 27.01.2014


Ответы (2)


Подход Haskell состоит в том, чтобы иметь разные типы для Complex Float и Complex Int, а не пытаться объединить их в один тип. С классами типов вы можете определить все эти типы одновременно:

data Complex a = C a a

instance Num a => Num (Complex a) where
  (C x y) + (C u v) = C (x+u) (y+v)
  (C x y) * (C u v) = C (x*u-y*v) (x*v+y*u)
  fromInteger n = C (fromInteger n) 0
  ...

Это сразу определяет Complex Int, Complex Double, Complex Rational и т. д. Более того, оно даже определяет Complex (Complex Int).

Обратите внимание, что это не определяет, как добавить Complex Int к Complex Double. Сложение (+) по-прежнему имеет тип (+) :: a -> a -> a, поэтому вы можете добавить только Complex Int к Complex Int и Complex Double к другому Complex Double.

Чтобы добавить числа разных типов, вы должны явно преобразовать их, например:

addIntToComplex :: Int -> Complex Double -> Complex Double
addIntToComplex n z = z + fromIntegral n

Взгляните на http://www.haskell.org/tutorial/numbers.html. раздел 10.3 для более полезных функций преобразования между классами числовых типов Haskell.

Обновление:

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

Например, рассмотрим это определение:

onethird = 1 / 3

Это представляет общее значение «1/3» во всех классах чисел:

import Data.Ratio

main = do
    putStrLn $ "as a Double: " ++ show (onethird :: Double)
    putStrLn $ "as a Complex Double: " ++ show (onethird :: Complex Double)
    putStrLn $ "as a Ratio Int: " ++ show (onethird :: Ratio Int)
    putStrLn $ "as a Complex (Ratio Int): " ++ show (onethird :: Complex (Ratio Int))
    ...

В некотором смысле Haskell позволяет «пользователю» решать, какому числовому типу следует оценивать выражение.

person ErikR    schedule 26.01.2014
comment
Я использовал Data.Complex, извините - и я тоже сделал несколько ошибок в коде, я обновлю его. - person user3125280; 26.01.2014
comment
Итак, для разработки класса типов Data.Complex уже существует, и я хотел бы знать, могу ли я как-то избежать написания ComplexNum. Я предполагаю, что это, скорее всего, будет связано с созданием экземпляра Complex for number и добавлением функций (+) и т. Д. Их нужно несколько унифицировать, а хотелось бы иметь комплексные числа для любых действительных чисел. - person user3125280; 26.01.2014
comment
спасибо, я ценю ответ, но на самом деле это не ответ на мой вопрос - я только хотел знать, могу ли я использовать класс Complex в Data.Complex. Однако в этом классе типов нет instance Num a => Num (Complex a) where (или дробного вместо num в моем случае), поэтому я не могу просто экземпляр num/fractal для моего типа Number. Так что реальный ответ - просто "сделай сам". - person user3125280; 26.01.2014

Это не похоже на законный код Haskell. У вас есть три конструктора типа ComplexNum, все с именами Complex. Кроме того, типы данных должны начинаться с заглавной буквы, поэтому foo не является допустимым типом. Трудно сказать, что вы имеете в виду, но я попробую:

Если у вас есть тип

data Complex a = (a,a)

вы можете сохранить свое определение Number и определить foo как:

data Foo = N Number
         | C (Complex Number)
person crockeea    schedule 26.01.2014
comment
извините за мою ошибку, у них были разные конструкторы, но сложные типы Integer и т. д. - из Data.Complex - person user3125280; 26.01.2014