Давайте подумаем о том, что вы хотите сделать. У вас есть список, и вы хотите (a) выбрать только определенные элементы из списка и (b) сделать что-то для каждого элемента списка. Это Хаскелл, давайте выражаем это в типах. Первое, что вам нужно - ну, он должен будет взять список [a]
и способ проверить, хорош ли каждый элемент. Как это можно проверить? Ну, это должна быть функция a -> Bool
. И это должно вернуть нам меньший список. Другими словами, что-то вроде [a] -> (a -> Bool) -> [a]
. Затем мы хотим взять наш список и сделать что-то для каждого элемента. Другими словами, нам понадобится список [a]
и функция a -> b
. Таким образом, нам нужно что-то типа [a] -> (a -> b) -> [b]
. Теперь, когда у нас есть типы, мы золотые: мы можем использовать Hoogle для их поиска. I высоко, настоятельно рекомендуем регулярно использовать Hoogle; это поисковая система Haskell, которая ищет как типы - уникальные удивительные имена частей и функций/типов данных/типов/модулей/модулей. first function, как выясняется, является вторым результатом для запроса: filter :: (a -> Bool) -> [a] -> [a]
.Это принимает функцию и список и возвращает только те элементы списка, для которых функция истинна. second function - это первый результат, map :: (a -> b) -> [a] -> [b]
, который вызывает данную функцию для каждого элемента данного списка и возвращает список результатов. Обратите внимание, что аргументы сначала имеют функцию, а не список; это более естественно, как вы вскоре увидите.
Мы хотим поставить эти два вместе healthyPeople
:
healthyPeople :: PeopleStats -> [String]
healthyPeople sts = map (\(n,_,_) -> n) $ filter (\(_,h,w) -> healthy h w) sts
Это делает то, что вы хотите. $
является функциональным приложением, но эффективно группирует правую часть из-за его приоритета; это позволяет нам исключать круглые скобки. Здесь мы видим, почему приятно, что map
выполняет свою функцию; мы передаем ему функцию извлечения имени ((n,_,_)
- это шаблон, который будет соответствовать тройке и присвойте n
его первый элемент, игнорируя остальные два), а затем (через $
) отфильтрованный список.
Это хорошо, но не так, как я на самом деле его написал. Поскольку sts
является последним параметром функции и ее телу, это не нужно. По правде говоря, все функции в Haskell принимают только один аргумент; это означает, что если вы не пройдете достаточно аргументов, вы получите функцию, которая ожидает отсутствующих аргументов и возвращает результат. С помощью оператора-функции состава .
, это дает нам
healthyPeople :: PeopleStats -> [String]
healthyPeople = map (\(n,_,_) -> n) . filter (\(_,h,w) -> healthy h w)
И это, наверное, как я пишу это! Вы часто будете использовать map
и filter
; они являются настоящими рабочими лошадками в функциональном программировании.
Существует еще один идиоматический способ, которым вы можете написать healthyPeople
; Вы можете использовать список понимание, следующим образом:.
healthyPeople :: PeopleStats -> [String]
healthyPeople stats = [n | (n,h,w) <- stats, healthy h w]
Это читается как «построить список каждый n
таким образом, что (n,h,w)
является элементом stats
и healthy h w
верно Если какой-либо из шаблона соответствует или предикаты сбой (у вас может быть более одного, каждый из которых вам не нужен), этот элемент пропускается, в противном случае выполняется левая сторона |
.Это фактически другой способ записи версии map
/filter
.
Редактирование 1: Как и многие другие, ваши устройства выключены в bmi
; вы должны иметь heightCm/100
.Кроме того, ваша healthy
функция имеет код, эквивалентный
f x | cond = True
| otherwise = False
Это эквивалентно записи, в C-подобный,
bool f(some_type x) {
if (cond)
return true;
else
return false;
}
Вместо этого, вы должны просто написать
bool f(some_type x) {
return cond;
}
Или, в этом случае
f x = cond
Это дает короткий код
healthy :: Height -> Weight -> Bool
healthy heightCm weightKg = let index = bmi heightCm weightKg
in 25 > index && 18 < index
(Вы можете использовать пункт where
тоже, но вот let
только потому, что мне нравится это лучше :))
Вы, кажется, потеряли некоторые отступы в определении «здоровый». Высота и вес для примера также выглядят необычно. –