Подтвердить что ты не робот

Почему Haskell/GHC не поддерживает переписывание имен файлов

Я новичок Haskell. Я заметил, что Haskell не поддерживает перегрузку имен:

-- Records.hs

data Employee = Employee
  { firstName :: String
  , lastName :: String
  , ssn :: String
  } deriving (Show, Eq)

data Manager = Manager
  { firstName :: String
  , lastName :: String
  , ssn :: String
  , subordinates :: [Employee]
  } deriving (Show, Eq)

Когда я скомпилирую это, я получаю:

[1 of 1] Compiling Main             ( Records.hs, Records.o )

Records.hs:10:5:
    Multiple declarations of `firstName'
    Declared at: Records.hs:4:5
                 Records.hs:10:5

Records.hs:11:5:
    Multiple declarations of `lastName'
    Declared at: Records.hs:5:5
                 Records.hs:11:5

Records.hs:12:5:
    Multiple declarations of `ssn'
    Declared at: Records.hs:6:5
                 Records.hs:12:5

Учитывая "силу" системы типа Haskell, кажется, что компилятору должно быть легко определить, какое поле для доступа в

emp = Employee "Joe" "Smith" "111-22-3333"
man = Manager "Mary" "Jones" "333-22-1111" [emp]
firstName man
firstName emp

Есть ли какая-то проблема, которую я не вижу. Я знаю, что отчет Haskell не позволяет этого, но почему бы и нет?

4b9b3361

Ответ 2

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

В частности, это:

data Employee = Employee
  { firstName :: String
  , lastName :: String
  , ssn :: String
  } deriving (Show, Eq)

генерирует (помимо прочего) функцию firstName :: Employee -> String.

Если вы также разрешите в том же модуле этого типа:

data Manager = Manager
  { firstName :: String
  , lastName :: String
  , ssn :: String
  , subordinates :: [Employee]
  } deriving (Show, Eq)

то каким будет тип функции firstName?

Это должно быть две отдельные функции, перегружающие одно и то же имя, которое Haskell не позволяет. Если вы не предполагаете, что это неявно генерирует класс typeclass и создает экземпляры для всего с полем с именем firstName (становится беспорядочным в общем случае, когда поля могут иметь разные типы), то текущая система записи Haskell не собирается чтобы иметь возможность поддерживать несколько полей с тем же именем в одном модуле. В настоящее время Хаскелл даже не пытается сделать такую ​​вещь.

Конечно, это можно было бы сделать лучше. Но есть некоторые сложные проблемы для решения, и, по сути, никто не придумывает решений для них, которые убедили всех, что есть самое перспективное направление для продвижения.

Ответ 3

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

Вы можете создать один модуль для сотрудника, например

module Model.Employee where

data Employee = Employee
  { firstName :: String
  , lastName :: String
  , ssn :: String
  } deriving (Show, Eq)

И один модуль для Менеджера, например:

module Model.Manager where

import Model.Employee (Employee)

data Manager = Manager
  { firstName :: String
  , lastName :: String
  , ssn :: String
  , subordinates :: [Employee]
  } deriving (Show, Eq)

И затем, где бы вы ни захотели использовать эти два типа данных, вы можете импортировать их и получить доступ к ним следующим образом:

import           Model.Employee (Employee)
import qualified Model.Employee as Employee
import           Model.Manager (Manager)
import qualified Model.Manager as Manager

emp = Employee "Joe" "Smith" "111-22-3333"
man = Manager "Mary" "Jones" "333-22-1111" [emp]

name1 = Manager.firstName man
name2 = Employee.firstName emp

Имейте в виду, что в конце концов вы используете два разных типа данных, и, таким образом, Manger.firstName - это еще одна функция, чем Employee.firstName, даже если вы знаете, что оба типа данных представляют человека, и у каждого человека есть имя. Но вам решать, как далеко вы перейдете к абстрактным типам данных, например, для создания типа данных Person из этих "коллекций атрибутов".