Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Область видимости декларации whereСодержание книги
Поиск на нашем сайте
Переменные, которые мы определили в секции where нашей фун- кции, видимы только ей самой, так что можно не беспокоиться о том, что мы засоряем пространство имён других функций. Если же нам нужны переменные, доступные в нескольких различных функциях, их следует определить глобально. Привязки в секции where не являются общими для различных образцов данной функ- ции. Предположим, что мы хотим написать функцию, которая при- нимает на вход имя человека и, если это имя ей знакомо, вежливо его приветствует, а если нет – тоже приветствует, но несколько гру- бее. Первая попытка может выглядеть примерно так: greet:: String -> String greet "Хуан" = niceGreeting ++ " Хуан!" greet "Фернандо" = niceGreeting ++ " Фернандо!" greet name = badGreeting ++ " " ++ name where niceGreeting = "Привет! Так приятно тебя увидеть," badGreeting = "О, чёрт, это ты," Однако эта функция работать не будет, так как имена, введён- ные в блоке where, видимы только в последнем варианте определе-
ния функции. Исправить положение может только глобальное оп- ределение функций niceGreeting и badGreeting, например: badGreeting:: String badGreeting = "О, чёрт, это ты,"
niceGreeting:: String niceGreeting = "Привет! Так приятно тебя увидеть,"
greet:: String -> String greet "Хуан" = niceGreeting ++ " Хуан!" greet "Фернандо" = niceGreeting ++ " Фернандо!" greet name = badGreeting ++ " " ++ name
Сопоставление с образцами в секции where Можно использовать привязки в секции where и для сопоставления с образцом. Перепишем секцию where в нашей функции так: ... where bmi = weight / height 2 (skinny, normal, fat) = (18.5, 25.0, 30.0) Давайте создадим ещё одну простую функцию, которая прини- мает два аргумента: имя и фамилию, и возвращает инициалы. initials:: String –> String –> String initials firstname lastname = [f] ++ ". " ++ [l] ++ "." where (f:_) = firstname (l:_) = lastname Можно было бы выполнять сопоставление с образцом прямо в параметрах функции (это проще и понятнее), но мы хотим пока- зать, что это допускается сделать и в определениях после ключево- го слова where.
Функции в блоке where Точно так же, как мы определяли константы в секции where, можно определять и функции. Придерживаясь нашей темы «здорового» программирования, создадим функцию, которая принимает спи- сок из пар «вес–рост» и возвращает список из ИМТ.
calcBmis:: [(Double, Double)] –> [Double] calcBmis xs = [bmi w h | (w, h) <– xs] where bmi weight height = weight / height 2 Видите, что происходит? Причина, по которой нам пришлось представить bmi в виде функции в данном примере, заключается в том, что мы не можем просто вычислить один ИМТ для парамет- ров, переданных в функцию. Нам необходимо пройтись по всему списку и для каждой пары вычислить ИМТ.
Пусть будет let Определения, заданные с помо- щью ключевого слова let, очень похожи на определения в секциях where. Ключевое слово where – это синтаксическая конструкция, ко- торая позволяет вам связывать вы- ражения с переменными в конце функции; объявленные перемен- ные видны во всём теле функции, включая сторожевые условия. Ключевое же слово let позволяет связывать выражения с именами в любом месте функции; конструк- ции let сами по себе являются вы- ражениями, но их область видимости ограничена локальным кон- текстом. Таким образом, определение let, сделанное в охранном выражении, видно только в нём самом. Как и любые другие конструкции языка Haskell, которые ис- пользуются для привязывания имён к значениям, определения let могут быть использованы в сопоставлении с образцом. Посмотрим на них в действии! Вот как мы могли бы определить функцию, ко- торая вычисляет площадь поверхности цилиндра по высоте и ра- диусу: cylinder:: Double -> Double -> Double cylinder r h = let sideArea = 2 * pi * r * h
topArea = pi * r 2 in sideArea + 2 * topArea Общее выражение выглядит так: let < определения > in < выражение >. Имена, которые вы определили в части let, видимы в выражении после ключевого слова in. Как видите, мы могли бы воспользовать- ся ключевым словом where для той же цели. Обратите внимание, что имена также выровнены по одной вертикальной позиции. Ну и какая разница между определениями в секциях where и let? Прос- то, похоже, в секции let сначала следуют определения, а затем вы- ражение, а в секции where – наоборот. На самом деле различие в том, что определения let сами по себе являются выражениями. Определения в секциях where – прос- то синтаксические конструкции. Если нечто является выражением, то у него есть значение. "Фуу!" – это выражение, и 3+5 – выражение, и даже head [1,2,3]. Это означает, что определение let можно ис- пользовать практически где угодно, например: ghci> 4 * (let a = 9 in a + 1) + 2 42 Ключевое слово let подойдёт для определения локальных функций: ghci> [let square x = x * x in (square 5, square 3, square 2)] [(25,9,4)] Если нам надо привязать значения к нескольким переменным в одной строке, мы не можем записать их в столбик. Поэтому мы разделяем их точкой с запятой. ghci> (let a = 10; b = 20 in a*b, let foo="Эй, "; bar = "там!" in foo ++ bar) (200,"Эй, там!") Как мы уже говорили ранее, определения в секции let могут ис- пользоваться при сопоставлении с образцом. Они очень полезны, к примеру, для того, чтобы быстро разобрать кортеж на элементы и привязать значения элементов к переменным, а также в других подобных случаях. ghci> (let (a,b,c) = (1,2,3) in a+b+c) * 100 600
Если определения let настолько хороши, то почему бы только их всё время и не использовать? Ну, так как это всего лишь выражения, причём с локальной областью видимости, то их нельзя использовать в разных охранных выражениях. К тому же некоторые предпочита- ют, чтобы их переменные вычислялись после использования в теле функции, а не до того. Это позволяет сблизить тело функции с её именем и типом, что способствует большей читабельности.
|
|||||||||||||||||||||||||||||||||||||||||||||||||
Последнее изменение этой страницы: 2017-02-17; просмотров: 195; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.219.158.84 (0.006 с.) |