Путаница типов/видов в Haskell (возможно) в алгебраических типах данных

Я работаю над созданием своего собственного симулятора Diplomacy на Haskell, чтобы намочить ноги. .

Я считаю, что придумал достойное определение того, что такое заказ:

data Order = Hold Unit Territory
           | Move Unit Territory Territory
           | Support Unit Territory Unit Territory Territory
           | Convoy Fleet Territory Army Territory Territory
  deriving (Eq, Show)

Для тех, кто не знаком с игрой, приказы написаны в форме «Держать флот в Лондоне», «Перемещать флот в Лондон, Ла-Манш», «Поддерживать флот, флот, Ла-Манш, Северная Атлантика, середина Атлантического океана» или «Конвойный флот, армия Ла-Манша». Лондон Брест» и др.

Теперь, с определением Единицы как data Unit = Fleet | Army (deriving Eq, Show), я получаю сообщение об ошибке Not in scope: type constructor or class 'Fleet' в отношении моего определения Порядка.

Почему это?

Как я могу написать свои определения для Отрядов или Приказов (или мне следует сделать что-то другое), что позволит мне требовать, чтобы первым аргументом Конвоя был Флот, а третьим аргументом была Армия?

Я просто «даже не ошибся» в своем подходе к этой проблеме?

Должен ли я подойти к этому в моей функции проверки (потому что, насколько мне известно, нет СПОСОБНОСТИ указать только действительные заказы через Haskell. Это выразительно, но не НАСТОЛЬКО выразительно)?

Я уже пытался использовать «DataKinds», но это мне совсем не помогло (несмотря на постскриптум об ошибке, предлагающий сделать это, опять же, постскриптумы об ошибках Haskell предлагают много вещей, поэтому я сомневаюсь, что мне нужно уделять слишком много внимания Это).


person Eliza Brandt    schedule 01.08.2016    source источник
comment
Я что-то путаюсь в терминологии. Вы показываете свою ошибку при использовании типов данных, но затем спрашиваете, как превратить Fleet в класс типов? В любом случае вы получаете ошибку, потому что Fleet не является типом, это конструктор типа Unit. Я думаю, вам стоит немного переосмыслить свой дизайн. Кроме того, DataKinds определенно не то, что вам нужно. Это расширенная функция, которая здесь не применяется.   -  person pdexter    schedule 01.08.2016
comment
О, я... немного забыл, что сказал это. Спасибо за это. Обновление теперь исправило это.   -  person Eliza Brandt    schedule 01.08.2016


Ответы (1)


data Unit = Fleet | Army 

Unit — это тип. Его значения могут быть либо Fleet, либо Army — это не типы.

data Order = Hold Unit Territory
           | Move Unit Territory Territory
           | Support Unit Territory Unit Territory Territory
                     ^^^^           ^^^^

Это типы -- ОК.

           | Convoy Fleet Territory Army Territory Territory
                    ^^^^^           ^^^^

Это значения -- не в порядке. Строка выше очень похожа на

           | Convoy "hello" Territory 42 Territory Territory

что не имеет смысла.

Возможно, вы просто хотите использовать

           | Convoy Territory Territory Territory

но я не знаком с игрой, поэтому не знаю, что вам там вообще нужно.

Кроме того, забудьте о классах типов и расширении DataKinds — не используйте расширенные возможности, если они вам действительно не нужны.


Другой вариант, если вы планируете добавлять поля в Fleet и Army, состоит в том, чтобы превратить их в типы.

data Fleet = F String Int -- dummy fields, you can put none
data Army = A
data Unit = FleetUnit Fleet | ArmyUnit Army    -- added the types here
data Order = Hold Unit Territory
           | Move Unit Territory Territory
           | Support Unit Territory Unit Territory Territory
           | Convoy Fleet Territory Army Territory Territory

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

orderExample1 :: Order
orderExample1 = Convoy (F "test" 33) terr1 A terr2 terr3

orderExample2 :: Order
orderExample2 = Support (FleetUnit (F "test2" 55)) terr1 (ArmyUnit A) terr2 terr3

Выше F ... строит Fleet, затем FleetUnit ... превращает его в Unit и, наконец, Support ... превращает его в Order.

person chi    schedule 01.08.2016
comment
Я только что отредактировал свой пост, чтобы уточнить немного больше об этом. Судя по этому, я думаю, что просто пойду по маршруту функции проверки (прочитайте редактирование). Кроме того, я не знал, что классы типов и типы данных были продвинутыми (при условии, что я даже не знаю, что продвинутого в этом языке ... мне потребовалась пара полных дней, чтобы попытаться понять, что такое арифметика Пеано (+ ) определяется в терминах Succ...oy vey), я видел их повсюду на экранах ошибок. - person Eliza Brandt; 01.08.2016
comment
Я думаю, главный вопрос: есть ли поля у Fleet и Army? Как написано выше, они не несут с собой никакой информации. Если да, то какая выгода от передачи аргумента Fleet в Convoy, если вы уже знаете, что это единственное значение, которое может иметь этот аргумент? - person chi; 01.08.2016
comment
Сейчас у них нет полей, но я могу изменить это. Я не могу решить, хочу ли я, чтобы данная территория (по сути, локация, поэтому Ла-Манш будет территорией) могла иметь связанную с ней единицу, или я хочу, чтобы единица имела связанную с ней территорию. Я надеялся, что смогу сделать что-то вроде возможности написать Convoy (eliminate $ unit someTerritory) someTerritory otherTerritory или что-то в этом роде (где exclude просто удаляет Just from a Maybe или выдает ошибку - person Eliza Brandt; 01.08.2016
comment
Смотрите редактирование. Если вы хотите добавить поля, вы можете использовать больше типов, чтобы делать то, что вы хотите. - person chi; 01.08.2016
comment
Есть ли способ сделать что-то подобное в ООП, получая тип данных? По сути, говоря, что флот и армия - это Единицы, без необходимости их перестраивать? - person Eliza Brandt; 01.08.2016
comment
Давайте продолжим обсуждение в чате. - person Eliza Brandt; 02.08.2016