что такое "соответствующее значение типа` Integer` "и можно ли его написать;также новые типы - PullRequest
1 голос
/ 07 ноября 2019

В отчете Haskell 2010 в разделе 6.4.1 написано

Целочисленный литерал представляет применение функции fromInteger к соответствующему значению типа Integer.

* 1008. * Как выглядит это «подходящее значение»? Могу ли я написать это в исходном Haskell? Конечно, я мог бы написать
x :: Integer
x = 4

Но это уравнение эквивалентно

x = (fromInteger 4) :: Integer

Редактировать: хмм, чтобы избежать бесконечной регрессии, которая, вероятно, должна составлять

x = (fromInteger 4?) :: Integer

, в котором 4? - загадочное значение 4 для типа Integer.

, поэтому он выбирает перегрузку Integer для fromInteger. Тип литерала (в оригинале x = 4) по-прежнему 4 :: Num a => a, это не тип Integer.

Я думаю об этом относительно newtype s:

{-# LANGUAGE  GeneralisedNewtypeDeriving  #-}

newtype Age = MkAge Int  deriving (Num, Eq, Ord, Show)
                        -- fromInteger is in Num
y :: Age
y = 4  
z = (4 + 5 :: Age)      -- no decl for z, inferred :: Age

Если я попрошу show y, я увижу MkAge 4;если я спрашиваю show x, я вижу 4. Так есть ли какой-нибудь невидимый конструктор для Integer с?

Дополнительный q для newtype с: поскольку я могу написать z = (4 + 5 :: Age), действительно ли необходим конструктор MkAge?

mkAge2 :: Age -> Age
mkAge2 = id

w = mkAge2 4

mkAge3 :: Integer -> Age
mkAge3 = fromInteger

u = mkAge3 4

кажется, работает так же хорошо, если я хочу что-то префикс.

Ответы [ 2 ]

3 голосов
/ 07 ноября 2019

Могу ли я написать это в исходном Haskell?

Вроде.

Вы можете написать 4 :: Integer, но 4 уже является приложением fromIntegerв «соответствующее значение». :: Integer только выбирает соответствующую перегрузку для fromInteger. Приложение имеет тип Integer, поэтому оно может функционировать как магический мономорфный литерал.

newtype Age = MkAge Int  deriving (Num, Eq, Ord, Show)

Вы можете написать 4 :: Age сейчас, и это нормально. Это не имеет ничего общего с тем, что делает Show. Вы можете написать свой собственный Show экземпляр, который печатает простой 4 вместо MkAge 4. Вот как работают Show экземпляры для всех встроенных типов. Нижеследующее относится к GHC, другие реализации могут иметь разные детали, но общие принципы, вероятно, будут одинаковыми.

Prelude> :i Int
data Int = GHC.Types.I# Int#    -- Defined in ‘GHC.Types’
Prelude> :i Integer
data Integer
  = integer-gmp-1.0.2.0:GHC.Integer.Type.S# Int#
  | integer-gmp-1.0.2.0:GHC.Integer.Type.Jp# {-# UNPACK #-}integer-gmp-1.0.2.0:GHC.Integer.Type.BigNat
  | integer-gmp-1.0.2.0:GHC.Integer.Type.Jn# {-# UNPACK #-}integer-gmp-1.0.2.0:GHC.Integer.Type.BigNat
    -- Defined in ‘integer-gmp-1.0.2.0:GHC.Integer.Type’

Как вы можете видеть, существуют конструкторы данных (и они не что невидимо!) для Int и Integer. Мы можем использовать один для Int без проблем.

Prelude> :set -XMagicHash
Prelude> :t 3#
3# :: GHC.Prim.Int#
Prelude> :t GHC.Types.I# 3#
GHC.Types.I# 3# :: Int
Prelude> show 3
"3"
Prelude> show $ GHC.Types.I# 3#
"3"

ОК, мы построили Int с конструктором, который не мешает отображать его в виде простого 3 немного. Это приложение добросовестного конструктора к честному мономорфному литералу. А как насчет Integer?

Prelude> GHC.Integer.Type.S# 3#

<interactive>:16:1: error:
    Not in scope: data constructor ‘GHC.Integer.Type.S#’
    No module named ‘GHC.Integer.Type’ is imported.
Prelude>

Хмм.

Prelude> :m + GHC.Integer.Type

<no location info>: error:
    Could not load module ‘GHC.Integer.Type’
    it is a hidden module in the package ‘integer-gmp-1.0.2.0’

Итак, конструкторы Integer скрыты от программиста (намеренно, я полагаю). Но если бы вы писали GHC.Integer.Type, вы бы могли использовать GHC.Integer.Type.S# 3#. Он имеет тип Integer и снова является приложением добросовестного конструктора к честному мономорфному литералу.

0 голосов
/ 07 ноября 2019

4 :: Integer является таким значением;4 :: Int нет. Не путайте литерал 4 с семейством фактических значений, которые он представляет в исходном коде.

4 сам по себе имеет полиморфный тип Num a => a, что означает, что в правильном контексте вы можете«извлечь» из него значение типа 4 :: Integer. Такой контекст является вызовом fromInteger, так как он ожидает значение типа Integer в качестве аргумента, а не значение типа Num a => a.

Когда вы пишете x = 4 после объявления этого x действительно является значением типа Integer, компилятор позаботится о "извлечении" значения 4 :: Integer для вашего значения из литерала.


MkAge необходимо для проверки типа,mkAge2 4 работает именно потому, что вы определили (или, по крайней мере, получили) экземпляр Num для Age, что влечет за собой определение fromInteger :: Integer -> Age. mkAge2 неявно вызывает fromInteger для 4, чтобы вернуть MkAge 4, а , что - это значение, переданное mkAge2. Поэтому вам все еще нужно MkAge, вам просто не нужно использовать явно.

...