Использование фильтра с пользовательскими типами данных - PullRequest
3 голосов
/ 23 июня 2019

У меня есть эти типы данных:

data Command = Back Int | Front Val deriving (Show,Eq)
data Val = Val {first::Int, second::Int, third::Int} deriving (Show, Eq)
type Program = [Command]

У меня есть эта функция:

foo :: Program -> Int
foo list = length (filter (==Front Val {first, second, third}) list)

Цель состоит в том, чтобы узнать, сколько раз происходит Фронт, используя ТОЛЬКО ФИЛЬТР, и foo дает компиляциюошибка.Я не уверен, как представить целочисленную / val часть Front.

Ответы [ 2 ]

5 голосов
/ 23 июня 2019

Как сказал @WillemVanOnsem в своем ответе, используемый вами подход не работает.Попробуйте использовать filter (\x -> case x of { Front _ -> True; Back _ -> False }) list.Вы можете понять, как это работает, исходя из этого, но если вам понадобятся какие-либо дополнительные сведения:

  • \x -> case x of { Front _ -> True; Back _ -> False } - это лямбда-выражение .Он определяет безымянную (или анонимную ) функцию, которая принимает один параметр с именем x и возвращает значение, заданное case x of { Front _ -> True; Back _ -> False }.
  • case x of { Front _ -> True; Back _ -> False } выполняет сопоставление с шаблоном по x.Если x имеет форму Front _, где _ может быть чем угодно, то возвращается True;в противном случае возвращается False.Обычно это утверждение будет иметь следующий формат:
case x of
    Front _ -> True
    Back _ -> False

Но приведенный выше компактный синтаксис короче и поэтому лучше работает в этом случае.

  • Выше лямбда-выражение -который, как обсуждалось, возвращает True, когда его аргумент имеет форму Front _ - затем передается в filter в качестве аргумента.
5 голосов
/ 23 июня 2019

Нельзя использовать проверку на равенство (==) :: Eq a => a -> a -> Bool с такими переменными, как first и second, если они не имеют значения. Здесь вам нужно сопоставление с шаблоном .

Мы можем, например, использовать понимание списка:

foo :: Program -> Int
foo list = length [ v | <b>v@(Front _) <-</b> list ]

Нет необходимости сопоставлять параметр с Val {}, или Val _ _ _ и т. Д., Поскольку единственный конструктор данных для типа Val - Val.

Если вы думаете, что позже добавите больше конструкторов данных, вы можете добавить дополнительный подшаблон:

foo :: Program -> Int
foo list = length [ v | v@(Front <b>(Val {})</b>) <- list ]

Или мы можем выполнить сопоставление с образцом в функции и использовать filter :: (a -> Bool) -> [a] -> [a], например:

foo :: Program -> Int
foo = length . filter f
    where f <b>(Front _)</b> = True
          f _ = False

или если мы включим проверку конструктора данных Val:

foo :: Program -> Int
foo = length . filter f
    where f (Front <b>(Val {})</b>) = True
          f _ = False
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...