<html>
<head>
	<title>Abbreviated Lambdas for Fun and Profit</title>

<style type="text/css">html {
	position: relative;
	max-width: 1024px;
	height: 100%;
}
body {
	font-family: Helvetica, arial, sans-serif;
	font-size: 14px;
	line-height: 1.6;
	padding-top: 10px;
	padding-bottom: 10px;
	background-color: white;
	padding: 30px;
}
body>*:first-child {
	margin-top: 0 !important;
}
body>*:last-child {
	margin-bottom: 0 !important;
}
a {
	color: #4183C4;
}
a.absent {
	color: #cc0000;
}
a.anchor {
	display: block;
	padding-left: 30px;
	margin-left: -30px;
	cursor: pointer;
	position: absolute;
	top: 0;
	left: 0;
	bottom: 0;
}
h1, h2, h3, h4, h5, h6 {
	margin: 20px 0 10px;
	padding: 0;
	font-weight: bold;
	-webkit-font-smoothing: antialiased;
	cursor: text;
	position: relative;
}
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {
	background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA09pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoMTMuMCAyMDEyMDMwNS5tLjQxNSAyMDEyLzAzLzA1OjIxOjAwOjAwKSAgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OUM2NjlDQjI4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUM2NjlDQjM4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QzY2OUNCMDg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QzY2OUNCMTg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsQhXeAAAABfSURBVHjaYvz//z8DJYCRUgMYQAbAMBQIAvEqkBQWXI6sHqwHiwG70TTBxGaiWwjCTGgOUgJiF1J8wMRAIUA34B4Q76HUBelAfJYSA0CuMIEaRP8wGIkGMA54bgQIMACAmkXJi0hKJQAAAABJRU5ErkJggg==) no-repeat 10px center;
	text-decoration: none;
}
h1 tt, h1 code {
	font-size: inherit;
}
h2 tt, h2 code {
	font-size: inherit;
}
h3 tt, h3 code {
	font-size: inherit;
}
h4 tt, h4 code {
	font-size: inherit;
}
h5 tt, h5 code {
	font-size: inherit;
}
h6 tt, h6 code {
	font-size: inherit;
}
h1 {
	font-size: 28px;
	color: black;
}
h2 {
	font-size: 24px;
	border-bottom: 1px solid #cccccc;
	color: black;
}
h3 {
	font-size: 18px;
}
h4 {
	font-size: 16px;
}
h5 {
	font-size: 14px;
}
h6 {
	color: #777777;
	font-size: 14px;
}
p, blockquote, ol, dl, li, table, pre {
	margin: 15px 0;
}
hr {
	background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OENDRjNBN0E2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OENDRjNBN0I2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4Q0NGM0E3ODY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4Q0NGM0E3OTY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqqezsUAAAAfSURBVHjaYmRABcYwBiM2QSA4y4hNEKYDQxAEAAIMAHNGAzhkPOlYAAAAAElFTkSuQmCC) repeat-x 0 0;
	border: 0 none;
	color: #cccccc;
	height: 4px;
	padding: 0;
}
body>h2:first-child {
	margin-top: 0;
	padding-top: 0;
}
body>h1:first-child {
	margin-top: 0;
	padding-top: 0;
}
body>h1:first-child+h2 {
	margin-top: 0;
	padding-top: 0;
}
body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
	margin-top: 0;
	padding-top: 0;
}
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
	margin-top: 0;
	padding-top: 0;
}
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
	margin-top: 0;
}
li p.first {
	display: inline-block;
}
li {
	margin: 0;
}
ol {
	padding-left: 30px;
}
ul :first-child, ol :first-child {
	margin-top: 0;
}
dl {
	padding: 0;
}
dl dt {
	font-size: 14px;
	font-weight: bold;
	font-style: italic;
	padding: 0;
	margin: 15px 0 5px;
}
dl dt:first-child {
	padding: 0;
}
dl dt> :first-child {
	margin-top: 0;
}
dl dt> :last-child {
	margin-bottom: 0;
}
dl dd {
	margin: 0 0 15px;
	padding: 0 15px;
}
dl dd> :first-child {
	margin-top: 0;
}
dl dd> :last-child {
	margin-bottom: 0;
}
blockquote {
	border-left: 4px solid #dddddd;
	padding: 0 15px;
	color: #777777;
}
blockquote> :first-child {
	margin-top: 0;
}
blockquote> :last-child {
	margin-bottom: 0;
}
table {
	padding: 0;
	border-collapse: collapse;
}
table tr {
	border-top: 1px solid #cccccc;
	background-color: white;
	margin: 0;
	padding: 0;
}
table tr:nth-child(2n) {
	background-color: #f8f8f8;
}
table tr th {
	font-weight: bold;
	border: 1px solid #cccccc;
	margin: 0;
	padding: 6px 13px;
}
table tr td {
	border: 1px solid #cccccc;
	margin: 0;
	padding: 6px 13px;
}
table tr th :first-child, table tr td :first-child {
	margin-top: 0;
}
table tr th :last-child, table tr td :last-child {
	margin-bottom: 0;
}
td {
	vertical-align: top;
}
img {
	max-width: 100%;
}
span.frame {
	display: block;
	overflow: hidden;
}
span.frame>span {
	border: 1px solid #dddddd;
	display: block;
	float: left;
	overflow: hidden;
	margin: 13px 0 0;
	padding: 7px;
	width: auto;
}
span.frame span img {
	display: block;
	float: left;
}
span.frame span span {
	clear: both;
	color: #333333;
	display: block;
	padding: 5px 0 0;
}
span.align-center {
	display: block;
	overflow: hidden;
	clear: both;
}
span.align-center>span {
	display: block;
	overflow: hidden;
	margin: 13px auto 0;
	text-align: center;
}
span.align-center span img {
	margin: 0 auto;
	text-align: center;
}
span.align-right {
	display: block;
	overflow: hidden;
	clear: both;
}
span.align-right>span {
	display: block;
	overflow: hidden;
	margin: 13px 0 0;
	text-align: right;
}
span.align-right span img {
	margin: 0;
	text-align: right;
}
span.float-left {
	display: block;
	margin-right: 13px;
	overflow: hidden;
	float: left;
}
span.float-left span {
	margin: 13px 0 0;
}
span.float-right {
	display: block;
	margin-left: 13px;
	overflow: hidden;
	float: right;
}
span.float-right>span {
	display: block;
	overflow: hidden;
	margin: 13px auto 0;
	text-align: right;
}
code, tt {
	margin: 0 2px;
	padding: 0 5px;
	white-space: nowrap;
	border: 1px solid #eaeaea;
	background-color: #f8f8f8;
	border-radius: 3px;
}
pre code {
	margin: 0;
	padding: 0;
	white-space: pre;
	border: none;
	background: transparent;
}
.highlight pre {
	background-color: #f8f8f8;
	border: 1px solid #cccccc;
	font-size: 13px;
	line-height: 19px;
	overflow: auto;
	padding: 6px 10px;
	border-radius: 3px;
}
pre {
	background-color: #f8f8f8;
	border: 1px solid #cccccc;
	font-size: 13px;
	line-height: 19px;
	overflow: auto;
	padding: 6px 10px;
	border-radius: 3px;
}
pre code, pre tt {
	background-color: transparent;
	border: none;
}
sup {
	font-size: 0.83em;
	vertical-align: super;
	line-height: 0;
}
kbd {
	display: inline-block;
	padding: 3px 5px;
	font-size: 11px;
	line-height: 10px;
	color: #555;
	vertical-align: middle;
	background-color: #fcfcfc;
	border: solid 1px #ccc;
	border-bottom-color: #bbb;
	border-radius: 3px;
	box-shadow: inset 0 -1px 0 #bbb
}
* {
	-webkit-print-color-adjust: exact;
}
ins {
	color: #00A000
}
del {
	color: #A00000
}
</style><style type="text/css">
/**
	* prism.js default theme for JavaScript, CSS and HTML
	* Based on dabblet (http://dabblet.com)
	* @author Lea Verou
	*/

code[class*="language-"], pre[class*="language-"] {
	color: black;
	background: none;
	text-shadow: 0 1px white;
	font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
	font-size: 11px;
	text-align: left;
	white-space: pre;
	word-spacing: normal;
	word-break: normal;
	word-wrap: normal;
	line-height: 1.5;
	-moz-tab-size: 4;
	-o-tab-size: 4;
	tab-size: 4;
	-webkit-hyphens: none;
	-moz-hyphens: none;
	-ms-hyphens: none;
	hyphens: none;
}
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
	text-shadow: none;
	background: #b3d4fc;
}
pre[class*="language-"]::selection, pre[class*="language-"] ::selection, code[class*="language-"]::selection, code[class*="language-"] ::selection {
	text-shadow: none;
	background: #b3d4fc;
}
@media print {
	code[class*="language-"], pre[class*="language-"] {
		text-shadow: none;
	}
}

/* Code blocks */

pre[class*="language-"] {
	padding: 1em;
	margin: .5em 0;
	overflow: auto;
}
:not(pre)>code[class*="language-"], pre[class*="language-"] {
	background: #f8f8f8;
}

/* Inline code */

:not(pre)>code[class*="language-"] {
	padding: .1em;
	border-radius: .3em;
	white-space: normal;
}
.token.comment, .token.prolog, .token.doctype, .token.cdata {
	color: slategray;
}
.token.punctuation {
	color: #999;
}
.namespace {
	opacity: .7;
}
.token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol, .token.deleted {
	color: #905;
}
.token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted {
	color: #690;
}
.token.operator {
	color: #a67f59;
}
.token.entity, .token.url, .language-css .token.string, .style .token.string {
	color: #a67f59;
	background: hsla(0, 0%, 100%, .5);
}
.token.atrule, .token.attr-value, .token.keyword {
	color: #07a;
}
.token.function {
	color: #DD4A68;
}
.token.regex, .token.important, .token.variable {
	color: #e90;
}
.token.important, .token.bold {
	font-weight: bold;
}
.token.italic {
	font-style: italic;
}
.token.entity {
	cursor: help;
}
</style>

<script type="text/javascript">
var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-(\w+)\b/i,t=0,n=_self.Prism={util:{encode:function(e){return e instanceof a?new a(e.type,n.util.encode(e.content),e.alias):"Array"===n.util.type(e)?e.map(n.util.encode):e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function(e){var t=n.util.type(e);switch(t){case"Object":var a={};for(var r in e)e.hasOwnProperty(r)&&(a[r]=n.util.clone(e[r]));return a;case"Array":return e.map&&e.map(function(e){return n.util.clone(e)})}return e}},languages:{extend:function(e,t){var a=n.util.clone(n.languages[e]);for(var r in t)a[r]=t[r];return a},insertBefore:function(e,t,a,r){r=r||n.languages;var l=r[e];if(2==arguments.length){a=arguments[1];for(var i in a)a.hasOwnProperty(i)&&(l[i]=a[i]);return l}var o={};for(var s in l)if(l.hasOwnProperty(s)){if(s==t)for(var i in a)a.hasOwnProperty(i)&&(o[i]=a[i]);o[s]=l[s]}return n.languages.DFS(n.languages,function(t,n){n===r[e]&&t!=e&&(this[t]=o)}),r[e]=o},DFS:function(e,t,a,r){r=r||{};for(var l in e)e.hasOwnProperty(l)&&(t.call(e,l,e[l],a||l),"Object"!==n.util.type(e[l])||r[n.util.objId(e[l])]?"Array"!==n.util.type(e[l])||r[n.util.objId(e[l])]||(r[n.util.objId(e[l])]=!0,n.languages.DFS(e[l],t,l,r)):(r[n.util.objId(e[l])]=!0,n.languages.DFS(e[l],t,null,r)))}},plugins:{},highlightAll:function(e,t){var a={callback:t,selector:'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'};n.hooks.run("before-highlightall",a);for(var r,l=a.elements||document.querySelectorAll(a.selector),i=0;r=l[i++];)n.highlightElement(r,e===!0,a.callback)},highlightElement:function(t,a,r){for(var l,i,o=t;o&&!e.test(o.className);)o=o.parentNode;o&&(l=(o.className.match(e)||[,""])[1],i=n.languages[l]),t.className=t.className.replace(e,"").replace(/\s+/g," ")+" language-"+l,o=t.parentNode,/pre/i.test(o.nodeName)&&(o.className=o.className.replace(e,"").replace(/\s+/g," ")+" language-"+l);var s=t.textContent,u={element:t,language:l,grammar:i,code:s};if(!s||!i)return n.hooks.run("complete",u),void 0;if(n.hooks.run("before-highlight",u),a&&_self.Worker){var c=new Worker(n.filename);c.onmessage=function(e){u.highlightedCode=e.data,n.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,r&&r.call(u.element),n.hooks.run("after-highlight",u),n.hooks.run("complete",u)},c.postMessage(JSON.stringify({language:u.language,code:u.code,immediateClose:!0}))}else u.highlightedCode=n.highlight(u.code,u.grammar,u.language),n.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,r&&r.call(t),n.hooks.run("after-highlight",u),n.hooks.run("complete",u)},highlight:function(e,t,r){var l=n.tokenize(e,t);return a.stringify(n.util.encode(l),r)},tokenize:function(e,t){var a=n.Token,r=[e],l=t.rest;if(l){for(var i in l)t[i]=l[i];delete t.rest}e:for(var i in t)if(t.hasOwnProperty(i)&&t[i]){var o=t[i];o="Array"===n.util.type(o)?o:[o];for(var s=0;s<o.length;++s){var u=o[s],c=u.inside,g=!!u.lookbehind,h=!!u.greedy,f=0,d=u.alias;u=u.pattern||u;for(var p=0;p<r.length;p++){var m=r[p];if(r.length>e.length)break e;if(!(m instanceof a)){u.lastIndex=0;var y=u.exec(m),v=1;if(!y&&h&&p!=r.length-1){var b=r[p+1].matchedStr||r[p+1],k=m+b;if(p<r.length-2&&(k+=r[p+2].matchedStr||r[p+2]),u.lastIndex=0,y=u.exec(k),!y)continue;var w=y.index+(g?y[1].length:0);if(w>=m.length)continue;var _=y.index+y[0].length,P=m.length+b.length;if(v=3,P>=_){if(r[p+1].greedy)continue;v=2,k=k.slice(0,P)}m=k}if(y){g&&(f=y[1].length);var w=y.index+f,y=y[0].slice(f),_=w+y.length,S=m.slice(0,w),O=m.slice(_),j=[p,v];S&&j.push(S);var A=new a(i,c?n.tokenize(y,c):y,d,y,h);j.push(A),O&&j.push(O),Array.prototype.splice.apply(r,j)}}}}}return r},hooks:{all:{},add:function(e,t){var a=n.hooks.all;a[e]=a[e]||[],a[e].push(t)},run:function(e,t){var a=n.hooks.all[e];if(a&&a.length)for(var r,l=0;r=a[l++];)r(t)}}},a=n.Token=function(e,t,n,a,r){this.type=e,this.content=t,this.alias=n,this.matchedStr=a||null,this.greedy=!!r};if(a.stringify=function(e,t,r){if("string"==typeof e)return e;if("Array"===n.util.type(e))return e.map(function(n){return a.stringify(n,t,e)}).join("");var l={type:e.type,content:a.stringify(e.content,t,r),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:r};if("comment"==l.type&&(l.attributes.spellcheck="true"),e.alias){var i="Array"===n.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}n.hooks.run("wrap",l);var o="";for(var s in l.attributes)o+=(o?" ":"")+s+'="'+(l.attributes[s]||"")+'"';return"<"+l.tag+' class="'+l.classes.join(" ")+'" '+o+">"+l.content+"</"+l.tag+">"},!_self.document)return _self.addEventListener?(_self.addEventListener("message",function(e){var t=JSON.parse(e.data),a=t.language,r=t.code,l=t.immediateClose;_self.postMessage(n.highlight(r,n.languages[a],a)),l&&_self.close()},!1),_self.Prism):_self.Prism;var r=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return r&&(n.filename=r.src,document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",n.highlightAll)),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
</script>

<script type="text/javascript">
Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:{pattern:/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/};
</script>

<script type="text/javascript">
Prism.languages.c=Prism.languages.extend("clike",{keyword:/\b(asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/,operator:/\-[>-]?|\+\+?|!=?|<<?=?|>>?=?|==?|&&?|\|?\||[~^%?*\/]/,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)[ful]*\b/i}),Prism.languages.insertBefore("c","string",{macro:{pattern:/(^\s*)#\s*[a-z]+([^\r\n\\]|\\.|\\(?:\r\n?|\n))*/im,lookbehind:!0,alias:"property",inside:{string:{pattern:/(#\s*include\s*)(<.+?>|("|')(\\?.)+?\3)/,lookbehind:!0},directive:{pattern:/(#\s*)\b(define|elif|else|endif|error|ifdef|ifndef|if|import|include|line|pragma|undef|using)\b/,lookbehind:!0,alias:"keyword"}}},constant:/\b(__FILE__|__LINE__|__DATE__|__TIME__|__TIMESTAMP__|__func__|EOF|NULL|stdin|stdout|stderr)\b/}),delete Prism.languages.c["class-name"],delete Prism.languages.c["boolean"];
</script>

<script type="text/javascript">
Prism.languages.cpp=Prism.languages.extend("c",{keyword:/\b(alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|float|for|friend|goto|if|inline|int|long|mutable|namespace|new|noexcept|nullptr|operator|private|protected|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,"boolean":/\b(true|false)\b/,operator:/[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|:{1,2}|={1,2}|\^|~|%|&{1,2}|\|?\||\?|\*|\/|\b(and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/}),Prism.languages.insertBefore("cpp","keyword",{"class-name":{pattern:/(class\s+)[a-z0-9_]+/i,lookbehind:!0}});
</script>

</head>
<body>

<address align=right>
Document number: P0573R2 <br />
Date: 2017-10-08 <br />
Audience: Evolution Working Group <br />
Reply-To: Barry Revzin &lt;barry.revzin@gmail.com> <br />
Tomasz Kamiński &lt;tomaszkam@gmail.com>
</address>
<hr/>
<h1 align=center>Abbreviated Lambdas for Fun and Profit</h1>

<h2>Contents</h2>

<ol>
<li><a href="#Motivation">Motivation</a></li>
<li><a href="#Proposal">Proposal</a></li>
<li><a href="#Examples">Examples</a></li>
<li><a href="#Hyper">Hyper-abbreviated lambdas</a></li>
<li><a href="#Priors">Prior Work and Effects on Existing Code</a></li>
<li><a href="#Revisions">Revision History</a></li>
<li><a href="#Acks">Acknowledgements and References</a></li>
</ol>

<a name="Motivation" ></a><h2>1. Motivation</h2>

<p>The introduction of lambdas in C++11 transformed the landscape of C++ tremendously by allowing users to write arbitrary functions, predicates, and callbacks in-situ. Suddenly, instead of having to write function objects somewhere far from the code, we could write them inline. C++14 improved lambdas both by expanding their functionality (with generic lambdas) and by making them shorter (by being able to use <code class="language-cpp">auto</code> instead of spelling out the full type name of the parameters).</p>

<p>While lambdas are at the point where nearly arbitrary functionality is possible, it is still cumbersome and at times unnecessarily verbose to write out lambdas in the simplest of cases. A disproportionate number of lambda expressions are extremely short, consisting solely of a single expression in the body. These simple lambdas typically occur in one (or more) of these situations:

<ul>
<li> Unary/Binary predicates into algorithms.
<li> Callbacks
<li> Binding - simply reordering or adding new arguments for other functions. Basically, a better <code class="language-cpp">std::bind</code>.
<li> Lifting - taking overloaded functions and lifting them into a generic lambda so that they can be passed into a function.
</ul>

The main idea linking all of these situations is that we're trying to lift an <i>expression</i> into a function. That expression isn't merely an implementation detail: it's the most important detail. The goal as a programmer is to, as transparently as possible, make the expression we want to use available as a function in the context we want to use it. But in all these cases, the amount of code necessary to write this transparent lambda is excessive compared to the actual functionality being expressed.

<p> A perfect example of this excessive and complicated code necessary to express a seemingly simple idea is the lifting of overload sets [1]. We cannot simply write:

<pre><code class="language-cpp">template &lt;class T>
T twice(T x) { return x + x; }

template &lt;class I>
void f(I first, I last) {
    transform(first, last, twice); // error
}
</code></pre>

<p>We need to wrap <code class="inline">twice</code> in a lambda. But the correct way to do that is quite complex. We need to keep lots of details in mind. First, we of course need a generic lambda:

<pre><code class="language-cpp">[](auto x) { return twice(x); }</code></pre>

But then, this incurs unnecessary copies in and out, so we would want to forward into and out of the lambda:

<pre><code class="language-cpp">[](auto&& x) { return twice(std::forward&lt;decltype(x)>(x)); }</code></pre>

But now, if <code class="inline">twice</code> returned a reference type, the lambda drops that. In order to mirror that properly, we would need a trailing return type:

<pre><code class="language-cpp">[](auto&& x) -> decltype(auto) { return twice(std::forward&lt;decltype(x)>(x)); }</code></pre>

The problems with this approach are more subtle, but no less real. 

<h3>1.1. SFINAE and <code class="language-cpp">noexcept</code></h3>

The motivation is to <i>transparently</i> wrap an expression to make it usable as a function. If we have an overload set, like:

<pre><code class="language-cpp">int& foo(int& ) noexcept;
std::string foo(char const* );</code></pre>

We can use <code class="language-cpp">foo</code> in generic code directly by name and query whether it's invocable with a given argument type and query whether it's <code class="language-cpp">noexcept</code> with a given argument type. This is <i>prima facie</i> important and useful. If we naively wrap <code class="language-cpp">foo</code> in a lambda that simply returns:

<pre><code class="language-cpp">[](auto&& arg) -> decltype(auto) { return foo(arg); }</code></pre>

<p>Then we immediately lose both abilities. This lambda is <i>never</i> <code class="language-cpp">noexcept</code>. Since the user took the effort and deliberately marked <code class="language-cpp">foo(int& )</code> as being <code class="language-cpp">noexcept</code>, we lose that information if we just drop it on the floor. This lambda also advertises itself as being invocable with any argument type, which can lead to problems. 

<p>With only a single expression, there is no advantage to writing <code class="language-cpp">decltype(auto)</code> over <code class="language-cpp">decltype(foo(arg))</code>. But in certain contexts, preferring the latter can be the difference between a program that compiles and does the expected thing - and a program that fails to compile.

<pre><code class="language-cpp">bool call_me_maybe(function&lt;bool(int)> );     // #1
bool call_me_maybe(function&lt;bool(string) > ); // #2

// non-SFINAE-friendly lambda
call_me_maybe([](auto x) { return x == 2; });                      // error! lots and lots of diagnostic

// SFINAE-friendly lambda
call_me_maybe([](auto x) -> decltype(x == 2) { return x == 2; });  // OK, calls #1</code></pre>

The intent of the programmer is simple, and the reason for the compile failure of the first attempt is quite complex (attempting to instantiate <code class="language-cpp">function&lt;bool(string)></code> involves instantiating the particular <code class="language-cpp">operator()</code> of the lambda to determine its return type, but this instantiation isn't considered in the immediate context and so this failure is a hard error rather than a substitution failure). The technique to fix this, the trailing <code class="language-cpp">decltype</code>, is an advanced technique - far more advanced than the problem seems to call for.


<h3>1.2. Does Concepts solve the problem?</h3>

<p> With Concepts, we have a better, clearer way to constrain templates. It's tempting to believe that the introduction of Concepts to C++2a would obviate us of this problem. But Concepts only helps us if we help Concepts.

<h4>1.2.1. Concept error messages</h4>

<p>Let's consider a constrained implementation of <code class="language-cpp">std::find_if</code>, where we only focus on the predicate constraint:

<pre><code class="language-cpp">template &lt;class F, class... Args>
concept Predicate = requires(F f, Args... args) {
    { std::invoke(f, args...) } -> bool;
};

template &lt;class Iter, Predicate&lt;typename std::iterator_traits&lt;Iter>::reference F>
Iter find_if(Iter, Iter, F );
</code></pre>

<p>Now, what happens when we try to invoke this incorrectly? 

<pre><code class="language-cpp">std::vector&lt;std::string> vs;
find_if(vs.begin(), vs.end(), [](auto const& s) { return s == 2; });                     // 1: Concept unfriendly
find_if(vs.begin(), vs.end(), [](auto const& s) -> decltype(s == 2) { return s == 2; }); // 2: Concept friendly</code></pre>

<p>Both invocations are erroneous. However, the non-Concept-friendly lambda generates <a href="https://wandbox.org/permlink/puI6CQH4UVyQzOU0">240 lines of errors</a>, going through all the various, irrelevant overloads of <code class="language-cpp">operator==</code> that don't work. 

<p>On the other hand, the second invocation, the Concept-friendly lambda, produces a short message clearly indicating that the lambda does not model the <code class="language-cpp">Predicate</code>. That error, in <a href="https://wandbox.org/permlink/diRMsYwPgHu2jYPp">its entirety</a>:

<pre style="padding-left: 30px">prog.cc:17:89: error: cannot call function 'Iterator find_if(Iterator, Iterator, F) [with Iterator = __gnu_cxx::__normal_iterator<std::__cxx11::basic_stringchar>*, std::vector<std::__cxx11::basic_string<char> > >; F = main()::<lambda(const auto:1&)>]'
   find_if(vs.begin(), vs.end(), [](auto const& s) -> decltype(s == 2) { return s == 2; }); //2
                                                                                         ^
prog.cc:11:10: note:   constraints not satisfied
 Iterator find_if(Iterator b, Iterator e, F f);
          ^~~~~~~
prog.cc:6:14: note: within 'template<class F, class ... T> concept const bool Predicate<F, T ...> [with F = main()::<lambda(const auto:1&)>; T = {std::__iterator_traits<__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > >, void>::reference}]'
 concept bool Predicate = requires(F f, T... t) {
              ^~~~~~~~~
prog.cc:6:14: note:     with 'main()::<lambda(const auto:1&)> f'
prog.cc:6:14: note:     with 'std::__cxx11::basic_string<char>& t#0'
prog.cc:6:14: note: the required expression 'f(t ...)' would be ill-formed</pre>

<h4>1.2.2. Concept overloading</h4>

<p>The situation is no better when we try to overload with Concepts. Consider a seemingly innocuous example where we try to implement <code class="language-cpp">on_each_month()</code>:

<pre><code class="language-cpp">void on_each_month(Predicate&lt;day_point> f);
void on_each_month(Predicate&lt;std::string_view> f);</code></pre>

<p>The intent of this function is to use the provided predicate to filter some set of dates. The first overload provides a <code class="language-cpp">day_point</code> in the numeric format, the second is an optimized version that provides a serialized date. Let's try to use one:

<pre><code class="language-cpp">on_each_month([](auto d) { return day_of_week(d) == friday; });</code></pre>

<p>Even though we might perceive that one overload is viable, but the other not, this call will also fail to compile due to a hard error in attempting to instantiate the <code class="language-cpp">string_view</code> overload (and again, with a very long list of diagnostics). This problem is the same fundamental problem demonstrated in the previous two examples. To fix this, the user either has to make the lambda non-generic, or constrain to only allow types that <code class="language-cpp">day_of_week()</code> accepts, or copy the entire body into a trailing decltype expression. All of these solutions are repetitive and more involved than we thought we needed.

<p>Neither the default <code class="language-cpp">auto</code> return type, nor the expression-agnostic <code class="language-cpp">decltype(auto)</code> as a trailing return type, are adequate solutions. To correctly solve the above issues, our initial wrapping of the overload set as:

<pre><code class="language-cpp">[](auto&& arg) -> decltype(auto) { return foo(arg); }</code></pre>

needs to be extended out all the way to:

<pre><code class="language-cpp">[](auto&& x) -> decltype(twice(std::forward&lt;decltype(x)>(x))) noexcept(noexcept(twice(std::forward&lt;decltype(x)>(x)))) { return twice(std::forward&lt;decltype(x)>(x)); }</code></pre>

Needless to say, this is an unsatisfactory solution. Moreover, it may be insufficient.

<h3>1.3. <code class="language-cpp">decltype(expr)</code> or <code class="language-cpp">decltype((expr))</code>?</h3>

For the most part, there is no difference between <code class="language-cpp">decltype(expr)</code> and <code class="language-cpp">decltype((expr))</code>, they yield the same type for many expressions. The only cases where they yield <i>different</i> types are when <code class="language-cpp">expr</code> is an <i>id-expression</i> or a class member access.

<pre><code class="language-cpp">auto lam1 = [](auto&& x) -> decltype(x)   { return x; };
auto lam2 = [](auto&& x) -> decltype((x)) { return x; };

int i;
lam1(i); // ok, returns int& because decltype(x) is int&
lam1(0); // error: can't bind lvalue to int&&
lam2(i); // ok, returns int& because x is an lvalue
lam2(0); // ok, returns int& because x is an lvalue

#define FWD(x) static_cast&lt;decltype(x)&&>(x) // see p0644
struct S { int x; };
auto getx1 = [](auto&& s) -> decltype(FWD(s).x)   { return FWD(s).x; };
auto getx2 = [](auto&& s) -> decltype((FWD(s).x)) { return FWD(s).x; };

S s{42};
getx1(s);            // returns int
getx1(std::move(s)); // returns int
getx2(s);            // returns int&
getx2(std::move(s)); // returns int&&
</code></pre>

For those functions that simply return class member access, <code class="language-cpp">decltype((expr))</code> is more likely to be the desired behavior. But this is a particularly subtle distinction. 

<h3>1.4. Potential for improvement</h3>

<p>In C++17 today, in order to lift an expression into a function, whether to be used as a callback or a predicate or a transformation, doing it properly is very difficult and very verbose. We need a trailing return type that wraps the whole expression, with an extra set or parentheses. We need a noexcept specification. This, in of itself, involves writing the function body in triplicate. 

<p>Furthermore, lambdas are unique in C++ in that they often are meaningless in a vacuum - they rely on the immediate context that comes from the expressions that contain them and code that precedes them. Since they often appear as sub-expressions, there is intrinsic value in making them shorter - if we can make them shorter by simply removing aspects of them that do not provide meaning to other readers of our code. 

<p>These issues arise in the context of function templates and member function templates as well. When the goal is to lift an expression into a function, the unnecessary boilerplate loses all expressiveness. This proposal seeks to eliminate this boilerplate in <i>simple</i> lambdas, function templates, and member function templates, without preventing users from writing the arbitrarily complex lambdas and functions that we can today.

<a name="Proposal"> </a><h2>2. Proposal</h2>

<p>This paper proposes several different enhancements to the language as it relates to lambdas and functions. While we believe that all of these changes have benefits to beginners and experts alike, and we hope to see them all adopted, we understand that they are somewhat orthogonal of each other and in an effort to faciliate discussion and to provide EWG with options, we present them as as a primary proposal and several extensions to it.

<h3>2.1. Primary Proposal: <code>=> <i>assignment-expression</i></code> for lambdas</h3>

<p>This paper proposes the creation of a new function body introducer for lambdas, <code class="language-cpp">=></code>, which allows for a single <i>assignment-expression</i> as the body that will be its return statement. The expression will also be used to synthesize a SFINAE-, Concept-, and <code class="language-cpp">noexcept</code>-friendly trailing return type. The <i>assignment-expression</i> will be used as body the body of the lambda and to determine a SFINAE- and noexcept-friendly return type. 

<p>That is, this lambda:

<pre><code class="language-cpp">[](auto&& a, auto&& b) => a.id() < b.id();</code></pre>

shall be treated as if it were written:

<pre><code class="language-cpp">[](auto&& a, auto&& b) -> decltype((a.id() < b.id())) noexcept(noexcept(a.id() < b.id())) { return a.id() < b.id(); }</code></pre>

<p>Note that there is no <code class="language-cpp">return</code> keyword used in the lambda body, it is unnecessary.

<p>Some clarifying examples of the implications of the lambda body being an <i>assignment-expression</i>:

<pre><code class="language-cpp">[&](auto&& x) => x[0](y)   // lambda taking a single forwarding reference named x and returns the result of invoking x[0] with y
([&](auto&& x) => x[0])(y) // lambda taking a single forwarding reference named x and returning x[0], immediately invoked with y
                           // effectively, y[0]

f([](auto&& x) => x, 4)    // invoke f with two arguments: an identity lambda and 4
f([](auto&& x) => (x, 4))  // invoke f with one argument: a lambda taking one argument and returning 4
</code></pre>

<p> While having the lambdas in this case have a return type of <code class="language-cpp">auto</code> and no <code class="language-cpp">noexcept</code>-specification is more consistent with the language as it stands, having simple lambdas and simple function templates have a return type of <code class="language-cpp">decltype((expression))</code> and <code class="language-cpp">noexcept</code>-specification of <code class="language-cpp">noexcept(noexcept(expression))</code> saves the user from typing a bunch of repetitive boilerplate, and gets us to the point where we can just write <i>simple</i> code that just does the Right Thing&trade;.

<h3>2.2. Extension: <code>=> <i>assignment-expression</i></code> for functions</h3>

<p>All the same motivation that applies to lambdas applies equally to functions. Hence, we propose that <code>=> <i>assignment-expression</i></code> be allowed for all functions as well. This would allow, for instance, a simplification of <code class="language-cpp">std::begin</code>:

<pre><code class="language-cpp">template &lt;class C> auto begin(C& c) -> decltype(c.begin()) { return c.begin(); } // C++14 today
template &lt;class C> auto begin(C& c) => c.begin();                                // this proposal</code></pre>

Except that now <code class="language-cpp">begin</code> would additionally be conditionally <code class="language-cpp">noexcept</code>.

<h3>2.3. Extension: Omitting types in lambda parameter declaration for abbreviated lambdas</h3>

<p>With C++14, <code class="language-cpp">auto&&</code> has become the safe default usage for lambdas. It's almost never wrong. Even if the lambda isn't intended to be used polymorphically, it's preferable to use <code class="language-cpp">auto&&</code> rather than writing out the full name of the type. But once we're always writing <code class="language-cpp">auto&&</code>, it itself doesn't actually have any meaning (if it ever did). Consider a predicate for sorting <code class="language-cpp">lib::Widget</code>s by id:

<pre><code class="language-cpp">// C++11
[](lib::Widget const& a, lib::Widget const& b) { return a.id() < b.id(); }

// C++14 - Widget is simply inferred
[](auto&& a, auto&& b) { return a.id() < b.id(); }
</code></pre>

It's a full third shorter to just use <code class="language-cpp">auto&&</code>, but what does <code class="language-cpp">auto&&</code> gives us at that point?   Moreover, in those cases where <code class="language-cpp">auto&&</code> is wrong, it's not easy to distinguish. For instance, it may be important to only accept lvalues. But there is very little difference between a lambda taking its argument by <code class="language-cpp">auto&</code> vs <code class="language-cpp">auto&&</code>. Indeed, it looks more like a typo than a deliberate choice. It may also be important to accept arguments by reference to <code class="language-cpp">const</code> (particularly where threading or COW is concerned). These situations are less common, but it's important to be able to visually distinguish between them in code - and the code we have today is often insufficiently different. 

<p>Hence, we propose that use of <code class="language-cpp">=></code> in lambdas, specifically, will allow for omitting types in the parameter list, defaulting to <code class="language-cpp">auto&&</code>. This flips the treatment of a single identifier from identifying an unnamed argument of that type to identifying a forwarding reference with that name:

<pre><code class="language-cpp">[](x, y) { ... }    // lambda taking two unnamed parameters of types x and y
[](x, y) => (...)   // lambda taking two forwarding references named x and y
[](x& ) => ...      // ill-formed

[](auto&&... xs) => f(xs...); // primary proposal: lambda taking pack of forwarding references
[](xs...) => f(xs...);        // with this extension
</code></pre>

Which allows the first example of this section to be rewritten as:

<pre><code class="language-cpp">[](auto&& a, auto&& b) { return a.id() < b.id(); } // C++14
[](a, b) => a.id() < b.id()                        // this proposal</code></pre>

<p>While types <i>may be</i> omitted, it is not mandatory.

<h3>2.4. Implementation Experience</h3>

An implementation of this proposal for gcc has been graciously provided by Bastien Penavayre on <a href="https://github.com/DaemonSnake/gcc-abbreviated-cpp-lambda">github</a>, along with a version of the <a href="http://www.gcc-abbreviated-lambdas-proposal.tk/">compiler explorer</a>.

<a name="Examples"></a><h2>3. Examples</h2>

Transparently binding an overloaded member functions <code class="language-cpp">func</code> to an instance <code class="language-cpp">obj</code>:

<pre><code class="language-cpp">// C++14
[&](auto&&... args) noexcept(noexcept(obj.func(std::forward&lt;decltype(args)>(args)...)))
        -> decltype((obj.func(std::forward&lt;decltype(args)>(args)...))) {
    return obj.func(std::forward&lt;decltype(args)>(args)...);
}

// this proposal
[&](args...) => obj.func(std::forward&lt;decltype(args)>(args)...)

// with p0644
[&](args...) => obj.func(>>args...)
</code></pre>

<p>Sorting in decreasing order. Currently, we would rely on one of the many <i>named</i> function objects in the standard library to do this for us. While we recommend programmers use the standard algorithms, the standard function objects aren't quite on that level. This proposal allows us to just use <code class="language-cpp">></code>. It's longer, but arguably clearer:

<pre><code class="language-cpp">std::sort(v.begin(), v.end(), std::greater{});   // C++17
std::sort(v.begin(), v.end(), [](x,y) => x > y); // this proposal</code></pre>

Once we move from directly working on the elements to working on other functions of the elements, the gain becomes much bigger. Sorting in decreasing order by ID is both shorter and much more readable:

<pre><code class="language-cpp">std::sort(v.begin(), v.end(), [](auto&& x, auto&& y) { return x.id() > y.id(); }); // C++14
std::sort(v.begin(), v.end(), std::greater{}, &lib::Widget::id);                   // Ranges TS, with projection*
                                                                                   // ... assuming id isn't overloaded
std::sort(v.begin(), v.end(), std::greater{}, [](auto&& w) -> decltype(auto) { return w.id(); }); 
                                                                                   // Ranges TS, if id() is overloaded and returns
                                                                                   // an expensive-to-copy type. Don't forget decltype(auto)!
std::sort(v.begin(), v.end(), [](x,y) => x.id() > y.id());                         // this proposal

</code></pre>

Transforming a vector into another vector using a map as the function. Here, it's important to avoid the extra copy, and this proposal makes it easy to do so:
<pre><code class="language-cpp">std::transform(v.begin(), v.end(), std::back_inserter(v2),
    [&](auto&& key) { return map.at(key); });                      // C++17: woops, extra copies!
std::transform(v.begin(), v.end(), std::back_inserter(v2),
    [&](auto&& key) -> decltype(auto) { return map.at(key); });    // C++17
std::transform(v.begin(), v.end(), std::back_inserter(v2),
    [&](key) => map.at(key));                                      // this proposal</code></pre>

Check if all of the elements have some predicate satisfied - by element directly:
<pre><code class="language-cpp">std::all_of(v.begin(), v.end(), [](auto&& elem) { return elem.done(); }); // C++14, direct
std::all_of(v.begin(), v.end(), std::mem_fn(&lib::Element::done));        // C++14, with pointers to member functions*
std::all_of(v.begin(), v.end(), [](e) => e.done());                       // this proposal
</code></pre>or on an external object:
<pre><code class="language-cpp">std::all_of(v.begin(), v.end(), [&](auto&& elem) { return obj.satisfied(elem); });      // C++14, directly
std::all_of(v.begin(), v.end(), std::bind(&lib::Element::satisfied, std::ref(obj), _1); // C++14, with std::bind*
std::all_of(v.begin(), v.end(), [&](elem) => obj.satisfied(elem));                      // this proposal
</code></pre>
Looking for an element by id:
<pre><code class="language-cpp">auto it = std::find_if(v.begin(), v.end(), [&](auto&& elem) { return elem.id() == id; }); // C++14
auto it = std::find(v.begin(), v.end(), id, &lib::Widget::id);                            // Ranges TS, with projection*
auto it = std::find_if(v.begin(), v.end(), [&](elem) => elem.id() == id);                 // this proposal</code></pre>

Number of pairwise matches between two containers, using <code class="language-cpp">std::inner_product</code> with two callables. With this proposal, it's actually a little longer, but importantly you don't have to know the names of things - you just write the expressions you want to write:
<pre><code class="language-cpp">int matches = std::inner_product(as.begin(), as.end(), bs.begin(), 0,   // C++14, example from cppreference.com
    std::plus<>(), std::equal_to<>()); 
int matches = std::inner_product(as.begin(), as.end(), bs.begin(), 0,   // this proposal
    [](a,b) => a + b, [](a,b) => a == b);</code></pre>

<p>Writing some overloads of getters:
<table style="width:100%"><tr><th style="width:50%">C++17</th><th>This proposal</th></tr>
<tr><td><pre style="background:transparent;border:0px"><code class="language-cpp">
T&        get() &       { return value; }
T const&  get() const&  { return value; }
T&&       get() &&      { return std::move(value); }
T const&& get() const&& { return std::move(value); }</code></pre></td>
<td><pre style="background:transparent;border:0px"><code class="language-cpp">
auto get() &       => value;
auto get() const&  => value;
auto get() &&      => std::move(value);
auto get() const&& => std::move(value);</code></pre></td>
</tr></table>
<p>Writing a negating function object:

<table style="width:100%">
<tr><th style="width:50%">C++17</th><th>This proposal</th></tr>
<tr><td><pre style="background:transparent;border:0px"><code class="language-cpp">template&lt;typename F>
class variadic_negator_functor
{
  F f_;

public:
  explicit variadic_negator_functor(F a_f) : f_(a_f) {}

  template&lt;typename... Args>
  auto operator()(Args&&... args)
    -> decltype(!this->f_(std::forward&lt;Args>(args)...))
    noexcept(noexcept(!this->f_(std::forward&lt;Args>(args)...)))
  { return !this->f_(std::forward&lt;Args>(args)...); }
  
  template&lt;typename... Args>
  auto operator()(Args&&... args) const
    -> decltype(!this->f_(std::forward&lt;Args>(args)...))
    noexcept(noexcept(!this->f_(std::forward&lt;Args>(args)...)))
  { return !this->f_(std::forward&lt;Args>(args)...); }  
  
  // ...
};</code></pre></td>
<td><pre style="background:transparent;border:0px"><code class="language-cpp">template&lt;typename F>
class variadic_negator_functor
{
  F f_;

public:
  explicit variadic_negator_functor(F a_f) : f_(a_f) {}

  template&lt;typename... Args>
  auto operator()(Args&&... args)
    => !this->f_(std::forward&lt;Args>(args)...);

  

  template&lt;typename... Args>
  auto operator()(Args&&... args) const
    => !this->f_(std::forward&lt;Args>(args)...);  

  

  // ...
};</code></pre></td>
</table>

<p>Having to use nested lambdas. Dropping one <code class="language-cpp">return</code> might not seem like much, until you need to do it multiple times, which comes up quite often in functional programming. Consider this selection of examples from <a href="https://github.com/boostorg/hana/tree/1873a828c5c44ec853d465c7ab0c7cb2f821d44b/include/boost/hana/functional">Boost.Hana</a>, courtesy of Louis Dionne (with some minor tweaks):

<table style="width:150%">
<tr><th style="width:33.33%">C++17</th><th style="width:33.33%">This proposal</th><th style="width:33.33%">This proposal + p0644</th></tr>
<tr><td><pre style="background:transparent;border:0px"><code class="language-cpp">constexpr auto always = [](auto x) {
    return [x(std::move(x))](auto const& ...y) -> decltype((x)) {
        return x;
    };
};</code></pre></td>
<td><pre style="background:transparent;border:0px"><code class="language-cpp">constexpr auto always = [](auto x) => 
    [x=std::move(x)](y...) => x;</code></pre></td>
<td><pre style="background:transparent;border:0px"><code class="language-cpp">constexpr auto always = [](x) => [x=>>x](y...) => x;</code></pre></td>
</tr>
<tr><td><pre style="background:transparent;border:0px"><code class="language-cpp">constexpr auto apply = [](auto&& f, auto&& ...x) -> decltype(auto) {
    return std::forward&lt;decltype(f)>(f)(
        std::forward&lt;decltype(x)>(x)...
    );
};</code></pre></td>
<td><pre style="background:transparent;border:0px"><code class="language-cpp">constexpr auto apply = [](f, xs...) => 
    std::forward&lt;decltype(f)>(f)(
        std::forward&lt;decltype(xs)>(xs)...);</code></pre></td>
<td><pre style="background:transparent;border:0px"><code class="language-cpp">constexpr auto apply = [](f, xs...) => (>>f)(>>xs...);</code></pre></td>
</tr>
<tr><td><pre style="background:transparent;border:0px"><code class="language-cpp">constexpr auto compose2 = [](auto f, auto g) -> decltype(auto) {
    return [f(std::move(f)), g(std::move(g))]
           (auto&& x, auto&& ...xs) -> decltype(auto) {
        return f(
            g(std::forward&lt;decltype(x)>(x)),
            std::forward&lt;decltype(xs)>(xs)...
        );
    };
};</code></pre></td>
<td><pre style="background:transparent;border:0px"><code class="language-cpp">constexpr auto compose2 = [](auto f, auto g) => 
    [f=std::move(f), g=std::move(g)](x, xs...) =>
        f(g(std::forward&lt;decltype(x)>(x)),
            std::forward&lt;decltype(xs)>(xs)...);</code></pre></td>
<td><pre style="background:transparent;border:0px"><code class="language-cpp">constexpr auto compose2 = [](f, g) => 
    [f=>>f, g=>>g](x, xs...) => f(g(>>x), >>xs...);
</tr>
<tr><td><pre style="background:transparent;border:0px"><code class="language-cpp">constexpr auto partial = [](auto f, auto ...x) {
    return [f(std::move(f)), x...](auto&& ...y) -> decltype(auto) {
        return f(x..., std::forward&lt;decltype(y)>(y)...);
    };
};</code></pre></td>
<td><pre style="background:transparent;border:0px"><code class="language-cpp">constexpr auto partial = [](auto f, auto... x) =>
    [f=std::move(f), x...](y...) =>
        f(x..., std::forward&lt;decltype(y)>(y)...);</code></pre></td>
<td><pre style="background:transparent;border:0px"><code class="language-cpp">constexpr auto partial = [](f, x...) =>
    [f=>>f, x=>>x...](y...) => f(x..., >>y...);
    
//with the addition of p0780, can forward the whole pack
//instead of having to copy</code></pre></td></tr>        
</table>
   
<p>In all of these cases, the function body - the expression we're trying to use - is really simple. Which is the point. Let's make it simpler to write simpler things. 

<a name="Hyper"> </a><h2>4. Hyper-abbreviated lambdas</h2>

<p>This proposal is about as abbreviated as you can get, without loss of clarity or functionality. But we can always go deeper. Any proposal on abbreviating lambdas would be incomplete without mentioning that numerous languages (including, but not limited to Swift, Elixir, and Scala), as well as the Boost.Lambda library, allow for writing expressions that themselves are callable. These refer to arguments by number and then synthesize a new closure. An example using Swift's syntax with the sorting by id predicate that we have been using throughout:

<pre><code class="language-cpp">[](auto&& a, auto&& b) { return a.id() < b.id(); } // C++14 (51 characters)
[](a, b) => a.id() < b.id()                        // this proposal (28)
$1.id() < $2.id()                                  // even more abbreviation (18)</code></pre>

or checking if an element satsifes an object's test:

<pre><code class="language-cpp">[&](auto&& elem) { return obj.satisfies(elem); }; // C++14 (50 characters)
[&](elem) => obj.satisfies(elem);                 // this proposal (34)
obj.satisfies($1);                                // even more abbreviation (19)</code></pre>

<p>While <code class="language-cpp">$</code> directly is probably not the best choice in C++, there are other characters currently unusable in this context whose meaning we could overload here (e.g. <code class="language-cpp">&</code>). In our opinion, this next step in abbreviation is unnecessary as this proposal gets you most of the way there and now we start moving towards a brevity that sacrifices some clarity. 

<p>Additionally, an earlier draft of this paper had proposed omitting the lambda capture entirely - with missing capture defaulting to <code class="language-cpp">[&]</code>. This would allow the
shortening the lambda <code class="language-cpp">[&](e) => obj.satisfies(e)</code> to <code class="language-cpp">(e) => obj.satisfies(e)</code> and possibly even to <code class="language-cpp">e => obj.satisfies(e)</code>. It has been pointed out that this would be quite difficult to parse for compilers, and it has relatively marginal benefit compared to the other proposed changes, so it has been removed. 

<a name="Priors"></a><h2>5. Prior Work and Effects on Existing Code</h2>

<p>The original paper introducing what are now generic lambdas [2] also proposed extensions for omitting the <i>type-specifier</i> and dropping the body of a lambda if it's a single expression. This paper provides a different path towards those that same goal. Another paper proposing the same abbreviating syntax [4] has been merged into this one. 

<p>The usage of <code class="language-cpp">=></code> (or the similar <code class="language-cpp">-></code>) in the context of lambdas appears in many, many programming languages of all varieties. A non-exhaustive sampling: C#, D, Erlang, F#, Haskell, Idris, Java, JavaScript, ML, OCaml, Swift. The widespread use is strongly suggestive that the syntax is easy to read and quite useful. 

<p>The sequence of characters <code class="language-cpp">=></code> can appear in code in rare scenarios, such as passing the address of the assignment operator as a template non-type argument: <code class="language-cpp">X&lt;&Y::operator=></code>. However, such usage is incredibly rare, so this proposal would have very limited effect on existing code. Thanks to Richard Smith for doing a search.

<a name="Revisions"> </a><h2>6. Revision History</h2>

<p>Since r0, this paper focused on a single syntax for abbreviating lambdas, and includes a stronger motivation for the need for SFINAE and <code class="language-cpp">noexcept</code>. The section on abbreviated forwarding has been pulled out into its own paper [3], and a new section has been introduced discussing expression-based lambdas. 

<p>Since r1, this paper has combined with P0238 [4], changing the proposed SFINAE-friendly syntax to deducing <code class="language-cpp">decltype((expr))</code> instead of <code class="language-cpp">decltype(expr)</code> and also applying to functions. This proposal also drops omitting the capture syntax, and splits out each of the desired outcomes as extensions from the core proposal of <code class="language-cpp">=> expr</code> for lambdas.

<a name="Acks"></a><h2>7. Acknowledgements and References</h2>

<p>Thanks to Andrew Sutton for considering and rejecting several bad iterations of this proposal. Thanks to Richard Smith and Daveed Vandevoorde for looking into the practicality of this design along with parsing issues. Thanks to Nicol Bolas for refocusing the paper. Thanks to John Shaw for putting up with many crazy ideas.

<p>Thanks especially to Adam Martin for presenting this proposal at Kona, and Nathan Myers for valuable feedback. Thanks to Casey Carter for presenting p0238 in Toronto and the valuable feedback from there.

<p>Thanks to Bastien Penavayre for providing an implementation for gcc.

<p> [1] <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0119r2.pdf">Overload sets as function arguments</a>
<p> [2] <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3418.pdf">Proposal for Generic (Polymorphic) Lambda Expressions</a>
<p> [3] <a href="http://wg21.link/p0644">Forward without forward</a>
<p> [4] <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0238r1.html">Return type deduction and SFINAE</a>

</body>
</html>