Опубликован: 19.09.2008 | Доступ: свободный | Студентов: 658 / 70 | Оценка: 4.50 / 5.00 | Длительность: 21:25:00
Лекция 4:

Выражения

3.10 Арифметические последовательности

aexp -> [ exp1 [, exp2] .. [exp3] ]

Перевод:

выражение-аргумента -> [ выражение1 [, выражение2] .. [выражение3] ]

Арифметическая последовательность [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-выражения

exp -> let decls in exp

Перевод:

выражение -> let списки-объявлений in выражение

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" .