Как распечатать результат добавления функции из класса Добавить из Fun с помощью функций типа

Ниже приведен код отсюда Развлечение с функциями типов

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, TypeFamilies #-}

-- Start basic
class Add a b where
  type SumTy a b
  add :: a -> b -> SumTy a b

instance Add Integer Double where
  type SumTy Integer Double = Double
  add x y = fromIntegral x + y

instance Add Double Integer where
  type SumTy Double Integer = Double
  add x y = x + fromIntegral y

instance (Num a) => Add a a where
  type SumTy a a = a
  add x y = x + y
-- End basic

Это код, который я пытаюсь запустить:

main = print $ show (add 1 1)

Вот результат:

No instance for (Show (SumTy a0 b0))
      arising from a use of `show'
    Possible fix: add an instance declaration for (Show (SumTy a0 b0))
    In the second argument of `($)', namely `show (add 1 1)'
    In the expression: print $ show (add 1 1)
    In an equation for `main': main = print $ show (add 1 1)

Я пробовал несколько вещей, таких как размещение «данных» везде:

Результат 1

Not a data constructor: `a'

Результат 2 (после удаления "instance (Num a)")

Multiple declarations of `Double'
Declared at: ...

как добавление некоторой функции:

class Add a b where
    type SumTy a b
    add :: a -> b -> SumTy a b
    s :: SumTy a b -> String

instance Add Integer Double where
    type SumTy Integer Double = Double
    add x y = fromIntegral x + y
    s (SumTy _ x) = show x

main = print $ show (s (add 1 2.0) )

с этим результатом:

Not in scope: data constructor `SumTy'

Как вы могли заметить, я застрял, поэтому любая помощь бесценна для меня. :)


person panurg    schedule 22.01.2013    source источник


Ответы (1)


Проблема в том, что недостаточно контекста, чтобы определить, какой экземпляр Add использовать, и, следовательно, невозможно определить тип результата. Поскольку ghc не знает, какие типы использовать, он сообщает о самой общей проблеме, нет экземпляра Show для универсального SumTy a b:

No instance for (Show (SumTy a0 b0))
      arising from a use of `show'
    Possible fix: add an instance declaration for (Show (SumTy a0 b0))
    In the second argument of `($)', namely `show (add 1 1)'
    In the expression: print $ show (add 1 1)
    In an equation for `main': main = print $ show (add 1 1)

Однако предлагаемое «Возможное исправление» здесь не требуется. Что вам нужно, так это указать типы аргументов для add, чтобы можно было определить используемый экземпляр и, следовательно, тип результата:

*TyFun> show (add (1 :: Int) (1 :: Int))
"2"
*TyFun> show (add (1 :: Integer) (1 :: Integer))
"2"
*TyFun> show (add (1 :: Integer) (1 :: Double))
"2.0"
*TyFun> show (add (1 :: Integer) (1 :: Float))

<interactive>:7:1:
    No instance for (Show (SumTy Integer Float))
      arising from a use of `show'
    Possible fix:
      add an instance declaration for (Show (SumTy Integer Float))
    In the expression: show (add (1 :: Integer) (1 :: Float))
    In an equation for `it':
        it = show (add (1 :: Integer) (1 :: Float))

<interactive>:7:7:
    No instance for (Add Integer Float) arising from a use of `add'
    Possible fix: add an instance declaration for (Add Integer Float)
    In the first argument of `show', namely
      `(add (1 :: Integer) (1 :: Float))'
    In the expression: show (add (1 :: Integer) (1 :: Float))
    In an equation for `it':
        it = show (add (1 :: Integer) (1 :: Float))
person Daniel Fischer    schedule 22.01.2013
comment
Отличный ответ. Большое спасибо. Может быть, вы могли бы помочь мне с написанием этой функции (из моего кода выше)? Я не понимаю, как написать подпись s. Это вообще возможно? - person panurg; 24.01.2013
comment
@panurg, в объявлении вашего экземпляра вы сопоставляете шаблон с SumTy, что неверно: SumTy - это всего лишь псевдоним типа, а не конструктор данных (это то, что вам говорит компилятор). Вы определили SumTy в своем экземпляре равным Double, поэтому везде в этом экземпляре использование типа SumTy Integer Double эквивалентно простому Double. Просто замените (SumTy _ x) на x, и все заработает. - person Vladimir Matveev; 24.01.2013
comment
@VladimirMatveev Я не знаю, как использовать s, которые вы описали в своем посте. Я пытался: s (2.0::Double) и получил следующее: Не удалось сопоставить тип SumTy a0 b0' with Double' в первом аргументе s', namely (2.0 :: Double)' Не могли бы вы объяснить мне, как мне его использовать? - person panurg; 24.01.2013
comment
@panurg, я думаю, ты прав. Я был уверен, что это сработает, но я попытался запустить его и получил именно вашу ошибку. Не знаю почему так происходит, может кто более знающий ответит. - person Vladimir Matveev; 25.01.2013
comment
@panurg Я думал, вы пытались добавить s просто как костыль, так как у вас были проблемы с вызовом add и печатью результата. С ассоциированным синонимом типа type SumTy a b использовать его нельзя, так как нет возможности определить типы a и b из SumTy a b, разные пары типов могут сопоставляться одному и тому же SumTy (уже делают, Integer и Double в обоих порядках сопоставить с Double), поэтому компилятор не может знать, какой экземпляр использовать. - person Daniel Fischer; 25.01.2013
comment
@DanielFischer, это было именно то, что я хотел, поэтому я сказал «Отличный ответ» и поэтому я отметил ваш ответ как принятый. Но я изучаю хаскель, поэтому мне было любопытно, хорошо ли я понимаю, что невозможно написать функцию s. Я не хотел дублировать вопрос о разнице между семействами типов данных и типов, поэтому я спросил об этом в комментарии к записи. Я что-то не так? Кстати, спасибо за ваш ответ о s. - person panurg; 29.01.2013
comment
@panurg Нет, ты не сделал ничего плохого. Запрашивать дополнительные разъяснения в комментариях совершенно нормально (пока речь идет об исходном вопросе, а иногда даже если и нет). Первоначально я игнорировал функцию s, потому что думал, что это попытка использовать костыль, который обречен на провал (вы могли бы иметь работающую версию s, если бы SumTy было связанным семейством данных, но это сделало бы add гораздо более неудобным), а не то, чем вы были очень интересно, извините. - person Daniel Fischer; 29.01.2013