---
title: 16.2.3
tags: The Racket Guide
slideOptions:
theme: white
slideNumber: 'c/t'
center: false
transition: 'none'
keyboard: true
width: '93%'
height: '100%'
---
<style>
/* basic design */
.reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6,
.reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p {
font-family: 'Meiryo UI', 'Source Sans Pro', Helvetica, sans-serif, 'Helvetica Neue', 'Helvetica', 'Arial', 'Hiragino Sans', 'ヒラギノ角ゴシック', YuGothic, 'Yu Gothic';
text-align: left;
line-height: 1.8;
letter-spacing: normal;
text-shadow: none;
word-wrap: break-word;
color: #444;
}
.reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5 {font-weight: normal;}, .reveal h6 {font-weight: bold;}
.reveal h1, .reveal h2, .reveal h3 {color: #2980b9;}
.reveal th {background: #DDD;}
.reveal section img {background:none; border:none; box-shadow:none; max-width: 95%; max-height: 95%;}
.reveal blockquote {width: 90%; padding: 0.5vw 3.0vw;}
.reveal table {margin: 1.0vw auto;}
.reveal code {line-height: 1.2;}
.reveal p, .reveal li {padding: 0vw; margin: 0vw;}
.reveal .box {margin: -0.5vw 1.5vw 2.0vw -1.5vw; padding: 0.5vw 1.5vw 0.5vw 1.5vw; background: #EEE; border-radius: 1.5vw;}
/* table design */
.reveal table {background: #f5f5f5;}
.reveal th {background: #444; color: #fff;}
.reveal td {position: relative; transition: all 300ms;}
.reveal tbody:hover td { color: transparent; text-shadow: 0 0 3px #aaa;}
.reveal tbody:hover tr:hover td {color: #444; text-shadow: 0 1px 0 #fff;}
/* blockquote design */
.reveal blockquote {
width: 90%;
padding: 0.5vw 0 0.5vw 6.0vw;
font-style: italic;
background: #f5f5f5;
}
.reveal blockquote:before{
position: absolute;
top: 0.1vw;
left: 1vw;
content: "\f10d";
font-family: FontAwesome;
color: #2980b9;
font-size: 3.0vw;
}
/* font size */
.reveal h1 {font-size: 5.0vw;}
.reveal h2 {font-size: 3.0vw;}
.reveal h3 {font-size: 2.8vw;}
.reveal h4 {font-size: 2.6vw;}
.reveal h5 {font-size: 1.8vw;}
.reveal h6 {font-size: 2.2vw;}
.reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p {font-size: 2.2vw;}
.reveal code {font-size: 1.6vw;}
/* new color */
.red {color: #EE6557;}
.blue {color: #16A6B6;}
/* split slide */
#right {left: -18.33%; text-align: left; float: left; width: 50%; z-index: -10;}
#left {left: 31.25%; text-align: left; float: left; width: 50%; z-index: -10;}
</style>
<style>
/* specific design */
.reveal h1 {
margin: 0% -100%;
padding: 2% 100% 4% 100%;
color: #fff;
background: #fffa5e; /* fallback for old browsers */
background: linear-gradient(-45deg, #f7f439, #54ffa4, #23A6D5, #238ed5);
background-size: 200% 200%;
animation: Gradient 60s ease infinite;
}
@keyframes Gradient {
0% {background-position: 0% 50%}
50% {background-position: 100% 50%}
100% {background-position: 0% 50%}
}
.reveal h2 {
text-align: center;
margin: -5% -50% 2% -50%;
padding: 3% 10% 1% 10%;
color: #fff;
background: #fffa5e; /* fallback for old browsers */
background: -webkit-linear-gradient(to right, #c74646, #fffa5e); /* Chrome 10-25, Safari 5.1-6 */
background: linear-gradient(to right, #c74646, #fffa5e); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
}
.reveal h4 {
text-align: center;
}
</style>
---
## 16.2.3 パターンと表現の混在:syntax-case
syntax-rulesが生成する手続きは、内部的にsyntax-eを使用して与えられた構文オブジェクトを分解し、datum->syntaxを使用して結果を構築します。syntax-rules形式では、パターンマッチングやテンプレート構築モードから任意のRacket式に移行する方法がありません。
syntax-case形式では、パターンマッチ、テンプレート構築、任意の式を混在させることができます。
```
(syntax-case stx-expr (literal-id ...)
[pattern expr]
...)
```
syntax-case形式は、syntax-ruleと異なり、手続きを生成しません。代わりに、パターンと照合する構文オブジェクトを決定する stx-expr 式で始まります。また、各syntax-case節は、パターンとテンプレートの代わりに、パターンとexprを持ちます。exprの中では、通常#'で省略されるシンタックスフォームがテンプレート構築モードに移行します。節のexprが#'で始まる場合、シンタックスルールフォームのようなものになります。
```ocaml
> (syntax->datum
(syntax-case #'(+ 1 2) ()
[(op n1 n2) #'(- n1 n2)]))
'(- 1 2)
```
swapマクロはdefine-syntax-ruleやsyntax-rulesの代わりにsyntax-caseを使って書くことができます。
```ocaml
(define-syntax (swap stx)
(syntax-case stx ()
[(swap x y) #'(let ([tmp x])
(set! x y)
(set! y tmp))]))
```
syntax-caseを使用する利点の1つは、swapのエラーレポートをより適切に提供できることです。例えば、swapのdefine-yntax-ruleの定義では、(swap x 2)は、2が識別子ではないため、set!の観点からシンタックスエラーが発生します。swapのsyntax-caseの実装を改良して、サブフォームを明示的にチェックすることができます。
```ocaml
(define-syntax (swap stx)
(syntax-case stx ()
[(swap x y)
(if (and (identifier? #'x)
(identifier? #'y))
#'(let ([tmp x])
(set! x y)
(set! y tmp))
(raise-syntax-error #f
"not an identifier"
stx
(if (identifier? #'x)
#'y
#'x)))]))
```
この定義では、(swap x 2)は、set!ではなくswapに起因するシンタックスエラーを提供しています。
swap の上記の定義では、#'x と #'y は、マクロ変換の結果として使用されていないにもかかわらず、テンプレートです。この例では、テンプレートが入力構文の一部にアクセスするためにどのように使用されるかを示しています(この場合、一部の形式をチェックするため)。また、#'x または #'y のマッチは raise-yntax-error の呼び出しで使用され、syntax-error メッセージが非識別子のソースの場所を直接示すことができます。