Изучай Haskell во имя добра! (Липовача) - страница 20

>ghci> zip [5,3,2,6,2,7,2,5,4,6,6] ["я","не","черепаха"]

>[(5,"я"),(3,"не"),(2,"черепаха")]

Более длинный список просто обрезается до длины более короткого! Поскольку язык Haskell ленив, мы можем объединить бесконечный список с конечным:

>ghci> zip [1..] ["яблоко", "апельсин", "вишня", "манго"]

>[(1,"яблоко"),(2,"апельсин"),(3,"вишня"),(4,"манго")]

В поисках прямоугольного треугольника

Давайте закончим главу задачей, в решении которой пригодятся и генераторы списков, и кортежи. Предположим, что требуется найти прямоугольный треугольник, удовлетворяющий всем следующим условиям:

• длины сторон являются целыми числами;

• длина каждой стороны меньше либо равна 10;

• периметр треугольника (то есть сумма длин сторон) равен 24.



Треугольник называется прямоугольным, если один из его углов является прямым (равен 90 градусам). Прямоугольные треугольники обладают полезным свойством: если возвести в квадрат длины сторон, образующих прямой угол, то сумма этих квадратов окажется равной квадрату стороны, противоположной прямому углу. На рисунке стороны, образующие прямой угол, помечены буквами >a и >b; сторона, противоположная прямому углу, помечена буквой >c. Эта сторона называется гипотенузой.

Первым делом построим все тройки, элементы которых меньше либо равны 10:

>ghci> let triples = [(a,b,c) | c <– [1..10], b <– [1..10], a <– [1..10]]

Мы просто собираем вместе три списка, и наша производящая функция объединяет их в тройки. Если вы вызовете функцию >triples в GHCi, то получите список из тысячи троек. Теперь добавим условие, позволяющее отфильтровать только те тройки, которые соответствуют длинам сторон прямоугольных треугольников. Мы также модифицируем эту функцию, приняв во внимание, что сторона >b не больше гипотенузы, и сторона >a не больше стороны >b.

>ghci> let rightTriangles = [ (a,b,c) | c <– [1..10], b <– [1..c], a <– [1..b], a 2 + b 2 == c 2]

ПРИМЕЧАНИЕ. В консоли интерпретатора GHCi невозможно определять программные сущности в нескольких строках. Но в данной книге нам иногда приходится разбивать определения на несколько строк, чтобы код помещался на странице. В противном случае книга оказалась бы такой широкоформатной, что для неё вам пришлось бы купить гигантский книжный шкаф!

Почти закончили. Теперь давайте модифицируем функцию, чтобы получить треугольники, периметр которых равен 24.

>ghci> let rightTriangles' = [ (a,b,c) | c <– [1..10], b <– [1..c], a <– [1..b], a 2 + b 2 == c 2, a+b+c == 24]

>ghci> rightTriangles'

>[(6,8,10)]

Вот и ответ! Это общий шаблон в функциональном программировании. Вы берёте начальный набор решений и затем применяете преобразования и фильтруете их, пока не получите результат.