Россия, Петерубрг, СПБ-ГПУ, 1998 |
Выражения
3.10 Арифметические последовательности
Перевод:
Арифметическая последовательность [e1, e2 .. e3] обозначает список значений типа t, где каждое из выражений ei имеет тип t, и t является экземпляром класса Enum.
Трансляция:
Для арифметических последовательностей выполняются следующие тождества:
[ e1 ... ] = enumFrom e1
[ e1,e2 ... ] = enumFromThen e1 e2
[ e1 ... e3 ] = enumFromTo e1 e3
[ e1,e2 ... e3 ]= enumFromThenTo e1 e2 e3
где enumFrom, enumFromThen, enumFromTo и enumFromThenTo являются методами класса Enum, определенные в Prelude (см. раздел 6.3.2).
Семантика арифметических последовательностей поэтому полностью зависит от объявления экземпляра для типа t. Для получения более детальной информации о том, какие типы Prelude являются подтипами Enum и какова их семантика, смотрите рздел 6.3.4.
3.11 Описание списка
aexp | -> | [ exp | qual1 , ... , qualn ] | (описание списка, n >= 1) |
qual | -> | pat <- exp | (генератор) |
| | let decls | (локальное объявление) | |
| | exp | (страж) |
Перевод:
выражение-аргумента | -> | [ выражение | квалификатор1 , ... , квалификаторn ] | (описание списка, n>=1 ) |
квалификатор | -> | образец <- выражение | (генератор) |
| | let списки-объявлений | (локальное объявление) | |
| | выражение | (страж) |
Описание списка имеет вид [ e | q1, ..., qn ], n>=1, где квалификаторы qi являются
- или генераторами вида p 7 >= e, где p - образец (см. раздел "3.17" ) типа t, а e - выражение типа [t],
- или стражами, которые являются произвольными выражениями типа Bool,
- или локальными связываниями имен, которые обеспечивают новые определения, используемые в генерируемом выражении e или последующих стражах и генераторах.
Такое описание списка возвращает список элементов, порожденный путем вычисления e в последовательных окружениях, созданных вложенным вычислением вглубину генераторов в списке квалификаторов. Связывание имен переменных происходит согласно правилам обычного сопоставления с образцом (см. раздел "3.17" ), и если сопоставление завершится неудачей, то соответствующий элемент списка будет просто пропущен. Таким образом,
[ x | xs <- [ [(1,2),(3,4)], [(5,4),(3,2)] ], (3,x) <- xs ]
порождает список [4,2]. Если квалификатор является стражем, то, для того чтобы предшествующее сопоставление с образцом завершилось успешно, необходимо, чтобы значение квалификатора равнялось True. Как обычно, связывания имен в описаниях списков могут скрыть связывания имен во внешних областях видимости, например,
[ x | x <- x, x <- x ]= [ z | y <- x, z <- y]
Трансляция:
Для описаний списков выполняются следующие тождества, которые могут быть использованы в качестве трансляции в ядро:
[ e | True ] = [e]
[ e | q ] = [ e | q, True ]
[ e | b, Q ] = if b then [ e | Q ] else []
[ e | p <- l, Q ] = let ok p = [ e | Q ]
ok _ = []
in concatMap ok l
[ e | let decls, Q ]= let decls in [ e | Q ]
где e - выражения, p - образцы, l - выражения, значениями которых являются списки, b - булевы выражения, decls - списки объявлений, q - квалификаторы, а Q - последовательности квалификаторов. ok - новая переменная. Функция concatMap и булево значение True определены в Prelude.
Как показывает трансляция описаний списков, переменные, связанные с помощью let, имеют полностью полиморфные типы, тогда как переменные, определенные с помощью >-, связаны лямбда-выражением и поэтому мономорфны (см. раздел "4.5.4" ).
3.12 Let-выражения
Перевод:
Let-выражения имеют общий вид let { d1 ; ... ; dn } in e и вводят вложенный, лексически ограниченный, взаимно рекурсивный список объявлений (в других языках let часто называют letrec ). Областью видимости объявлений является выражение e и правая часть объявлений. Объявления описаны в лекции "4" . Сопоставление и связывание образцов выполняется лениво, неявная - делает эти образцы неопровержимыми. Например,
let (x,y) = undefined in e
не вызовет ошибку времени выполнения до тех пор, пока x или y не будут вычислены.
Трансляция:
Динамическая семантика выражения let { d1 ; ... ; dn } в e0 охватывается следующей трансляцией: после удаления всех сигнатур типов каждое объявление di транслируется в уравнение вида pi = ei, где pi и ei - соответственно образцы и выражения, при этом используется трансляция в разделе "4.4.3" . Однажды сделав это, эти тождества выполняются, и это можно использовать в качестве трансляции в ядро:
let {p1=e1; ... ; pn=e1} in e0 = let (~p1, ... ,~pn) = (e1, ... ,en) in e0 let p = e1 in e0 = case e1 of ~p -> e0
где ни одна переменная в p не является свободной в e1
let p = e1 in e0 = let p = fix ( \ ~p -> e1) in e0
где fix - наименьший ассоциативный оператор. Обратите внимание на использование неопровержимого образца ~ p. Эта трансляция не сохраняет статическую семантику, потому что использование case препятствует полностью полиморфной типизации связанных переменных. Статическая семантика связываний имен в let-выражениях описана разделе "4.4.3" .