LINUX.ORG.RU

Пытаюсь разобраться в Haskell

 


1

2

Привет, ЛОР!
Возможно, мой вопрос довольно глупый, но очень хотелось бы всё-таки разобраться.
По какой причине в Haskell недопустимы конструкции типа Integer + Double? Если я правильно понял, дело в том, что (+) имеет тип Num a => a -> a -> a, т.е. оба аргумента должны быть одного типа. Но по какой причине так сделано, ведь они и так оба являются инстансами Num?

Deleted
Ответ на: комментарий от Deleted

Num — класс, а не тип.

Что бы было понятнее, почему не стоит расчитывать на бинарную операцию с аргументами разных типов, но одного класса, рассомтри типы Maybe и IO. Оба эти типа относятся к классу Monad, но конструкция Just 3 >>= print лишена смысла.

anonymous
()

потому что яблоко с апельсином можно сложить в свободной абелевой группе, порождённой яблоком и апельсином; ни яблочная, ни апельсиновая группы для этого не подходят

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

Можно сделать что-то такое:

{-# LANGUAGE FlexibleInstances #-}

class Adder a where
    (+^) :: a

instance Adder (Int -> Int -> Int) where
    (+^) a b = a + b


instance Adder (Int -> Double -> Double) where
    (+^) a b = (fromIntegral a) + b

И тогда:

*Main> (2 :: Int) +^ (3 :: Int) :: Int
5
*Main> (2 :: Int) +^ (3.0 :: Double) :: Double
5.0
Waterlaz ★★★★★
()
Последнее исправление: Waterlaz (всего исправлений: 1)

Числа с плавающей точкой не нужны.

anonymous
()
Ответ на: комментарий от dmitry_malikov
Prelude> let (_ :: Int) + (_ :: Double) = "four" :: String
Prelude> (1 :: Int) + (2 :: Int)

<interactive>:10:15:
    Couldn't match expected type `Double' with actual type `Int'
    In the second argument of `(+)', namely `(2 :: Int)'
    In the expression: (1 :: Int) + (2 :: Int)
    In an equation for `it': it = (1 :: Int) + (2 :: Int)
Prelude> 2.5 + 1

<interactive>:11:1:
    No instance for (Fractional Int)
      arising from the literal `2.5'
    Possible fix: add an instance declaration for (Fractional Int)
    In the first argument of `(+)', namely `2.5'
    In the expression: 2.5 + 1
    In an equation for `it': it = 2.5 + 1

Ну и что ты сделал?

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

Математики-пуристы от значка (+) ожидают поведения операции абелевой группы, то есть

class PlusOn (t :: *) where
  (+) :: t -> t -> t
  isAssoc :: (x y z :: t) -> (x + y) + z = x + (y + z)
  isComm :: (x y :: t) -> x + y = y + x

instance PlusOn Word/Int/Nat/Integer/... where
  (+) = ...
  isAssoc = ...
  isComm = ...

instance PlusOn Double where
  (+) = ...
  isAssoc = 0.1 + (0.2 + 0.3) != (0.1 + 0.2) + 0.3
  isComm = ...

так что плавающие числа тут пролетают. Плюс Integer !<: Double.

Если ослабить требования, до альтернативной алгебры, например, или до некой «морально» абелевой операции, или просто до магмы, то всё ещё остаётся обычный хаскельный мономорфизм для каждого инстанса класса.

Вот в языке с ООП t -> t -> t означает, вообще говоря, forall (x y z <: t). x -> y -> z — предполагается, что аналог class так же запускает ad-hoc полиморфизм по разным типам t, но каждый такой тип представляет собой (верхний) тип (объект, пространство расслоения) по которому производится slice в категории типов, то есть для которого выбирается набор подтипов (подъобъектов, баз) для которых строятся вложения/инъекции (мономорфизмы, сечения) в этот максимальный тип, в итоге получается предпорядок, частичный порядок и вплоть до решётки подтипов относительно этого верхнего типа, конкретные подтипы сами могут быть пространствами расслоений для последующих баз. Простейшие вложения это вложения на уровне машинной памяти (bool в int, например), хотя вообще подтип может образовываться произвольной характеристической эпи-функцией sup -> sub + 1 -> bool (так что вложение sub -> sup выбирается — конкретный мономорфизм как конструктивная поддержка аксиоме выбора). В итоге SomeIntType <: SomeFloatType, например, так что в языках типа си (some_int_type)1 + (some_float_type)2.3 вполне работает таким образом. Тут важно, что типы именно поднимаются автоматически в подходящий (из контекста) верхний тип, upcast по идее безопасен, а вся небезопасность от опускания типов (которая устраняется sup -> sub + 1, иначе говоря Sup -> Maybe Sub вместо Sup -> Sub).

И в крайнем случае может быть x -> y -> z, то есть forall (x' <: x) (y' <: y) (z' <: z). x' -> y' -> z', голый operator+ в C++ себя так ведёт, то есть вообще как угодно (ad-hoc по всем аргументам, плюс подтипирование).

В хаскеле такой <: изображается как тот же класс типов с вытекающим мультипараметризмом повсюду (либо сразу от мультипараметризма — как у Снойберга в classy-prelude, например).

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