Попытка составить список пользовательских типов данных в Haskell - PullRequest
0 голосов
/ 04 сентября 2018

Я довольно новичок в Haskell и пытаюсь создать список пользовательских типов данных с именем Human . Человек определяется следующим образом: данные Человек = Человек (Строка), поэтому Человек по сути является Строкой. Человек определяется тем, высокий ли он или низкий (S или T), женский или мужской (F или M), а также взрослым или ребенком (A или C).

Я попытался написать функцию, которая в основном дает мне список лиц для каждой возможной комбинации указанных выше значений, т.е. = ["SFA", "SFC," TMC "...]. Это то, что я пришел с этим далеко:

func :: ([Human], state)
func = (x, state_) where
remainingHumans = [[height, sex, age] | height <- ["T", "S"], sex <- ["M", "F"], age <- ["A", "C"]]
allHumans = [Person(human) | human <- subsequences remainingHumans, length human == 3]
x = head allHumans
state _ = allHumans \\ [x]

Я получаю эту ошибку при попытке скомпилировать программу:

Couldn't match type ‘[[Char]]’ with ‘Char’
  Expected type: String
    Actual type: [[[Char]]]

Поскольку я довольно новичок, я также довольно растерялся, как поступить. Любая помощь или советы будут очень ценны

1 Ответ

0 голосов
/ 04 сентября 2018

Я думаю, что поскольку height, sex и age по сути являются символами , вероятно, лучше представить их как символы. Таким образом, мы можем написать height <- ['T', 'S'] вместо height <- ["T", "S"] или даже короче height <- "TS". Если мы создадим список String с, мы не создадим String, но - хорошо - список String с.

Поскольку у вас есть доступ к символам, вы можете создать список из трех символов height, sex и age, создав список : String - это просто введите псевдоним для [Char].

Мы также можем сделать другие улучшения. Поскольку мы создаем список из трех элементов, длина всегда равна трем, поэтому нам не нужно проверять это позже в процессе, и мы можем сделать Human с (я полагаю, вы смешали Person и Human) непосредственно.

Вы указываете state в подписи, но это переменная типа. Это будет означать, что это может быть что угодно . Здесь, однако, это явно список Human с, поэтому вам нужно изменить sgianture на (Human, [Human]).

Наконец, нам не нужно создавать head для получения первого элемента, но мы можем использовать сопоставление с образцом, и при этом мы не должны удалять этот элемент из списка: поскольку все элементы уникальны, все остальные элементы находятся в хвост (и никакой другой элемент не находится в хвосте):

func :: ([Human], [Human])
func = (x, state_) where
    (x:state_) = [Human [height, sex, age] | height <- "TS", sex <- "MF", age <- "AC"]

Возможные улучшения

Я думаю, что моделирование может быть лучше, если вы определите Human как:

data Human = Human Height Sex Age
data Height = Tall | Small
data Sex = Male | Female
data Age = Adult | Child

Делая это, вы ограничиваете число людей, которые могут быть построены по проекту . Действительно, прямо сейчас может оказаться, что функция содержит небольшую ошибку и выдает Human "ABC" (символы не входят в «домен»), или Human "TM" (слишком мало символов), или Human "AMT" (порядок замены). Это может привести к большим проблемам в дальнейшем. Указывая домены и т. Д. В типе, функции просто не могут генерировать такие значения (хорошо, компилятор выдаст ошибку). Так что это дает вам «более сильные гарантии», что функция работает правильно Функция, конечно, может содержать семантическую ошибку .

Кроме того, определяя отдельные параметры, вы также обязываете каждого человека иметь эти три атрибута, и конструктор теперь curried .

Это также упростило бы процесс создания людей с помощью функций (<$>) :: f (a -> b) -> f a -> f b и (<*>) :: f (a -> b) -> f a -> f b:

Human <$> [Tall, Small] <*> [Male, Female] <*> [Adult, Child]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...