В коде:
oneChar :: Char -> Doc
oneChar c = case lookup c simpleEscapes of
Just r -> text r
Nothing | mustEscape c -> hexEscape c
| otherwise -> char c
where mustEscape c = c < ' ' || c == '\x7f' || c > '\xff'
simpleEscapes :: [(Char, String)]
simpleEscapes = zipWith ch "\b\n\f\r\t\\\"/" "bnfrt\\\"/"
where ch a b = (a, ['\\',b])
r не передается oneChar. Куда r прибывает из?
lookup c simpleEscapes
возвращает значение Maybe String
, которое может быть либо Nothing
, либо Just
. r
- это строка, содержащаяся в Just
, как определено строкой:
Just r -> text r
Если вы спрашиваете, где вводится идентификатор, то он связан с совпадением шаблона в операторе case
, точно так же, как идентификатор c
связан с совпадением шаблона в определении функции.
Любое соответствие шаблону может ввести новый идентификатор для связанного выражения:
(\(Just x) -> x) foo
let (Just x) = foo in x
f (Just x) = x
case foo of
Just x -> x
... все они вводят новый идентификатор x
. На самом деле, все они практически эквивалентны, потому что компилятор преобразует их в блоки case
.
Вы используете оператор case для значения, возвращаемого lookup c simpleEscapes, которое имеет тип Maybe. У Maybe есть два конструктора данных: Just и Nothing. Конструктор данных Just параметризуется одним значением, а конструктор данных Nothing не имеет параметров.
Таким образом, в данном случае r является формальным параметром конструктора данных Just: его фактическое значение в возвращаемом значении из lookup.
Ключевое слово case вводит соответствие шаблону, которое имеет форму case EXPR of (PATTERN -> EXPR) +
. Итак, Just r
- это шаблон, который соответствует результату поиска c simpleEscapes
. В шаблоне переменные могут быть связаны. В основном это означает, что если lookup c simpleEscapes
возвращает Just
, тогда r
будет привязан к значению внутри этого Just
и результат выражения будет текст r
.