{ "cells": [ { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ ":opt no-lint" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Untyped $πœ†$-calculus\n", "νƒ€μž…μ—†λŠ” λžŒλ‹€κ³„μ‚°λ²•μ˜ 문법과 쀄일 수 μžˆλŠ” 식(reducible expression)의 κ°œλ… 등에 λŒ€ν•΄ μ•Œμ•„λ³Έλ‹€.\n", "\n", "\"쀄일 수 μžˆλŠ” 식\"μ΄λΌλŠ” 말이 λ„ˆλ¬΄ κΈΈκΈ° λ•Œλ¬Έμ— 'μ£ΌλŠ”μ‹'(redex)κ³Ό 같은 μ€„μž„λ§μ„ 보톡 더 많이 μ‚¬μš©ν•œλ‹€." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 문법\n", "$ x \\in \\textit{Nm} $\n", "\n", "$ e \\in \\textit{Tm}\n", "\\\\ e ::=~ x ~\\mid~ (\\lambda x.e) ~\\mid~ (e_1~e_2)\n", "$\n", "\n", "보톡 μˆ˜ν•™μ—μ„œ $f(x) = x^2$κ³Ό 같이 μ •μ˜ν•˜λŠ” ν•¨μˆ˜ $f$λ₯Ό λžŒλ‹€κ³„μ‚°λ²•μ—μ„œλŠ” μ•„λž˜μ™€ 같은 λ°©μ‹μœΌλ‘œ ν‘œν˜„ν•œλ‹€.\n", "\n", "$(\\lambda x.x^2)$\n", "\n", "그리고 보톡 μˆ˜ν•™μ—μ„œ μ •μ˜λœ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λŠ” $f(3)$κ³Ό 같은 ν‘œν˜„μ€ λžŒλ‹€κ³„μ‚°λ²•μ—μ„œλŠ” κ΄„ν˜Έ 없이 ν•¨μˆ˜μ™€ 인자λ₯Ό λ‚˜μ—΄ν•˜μ—¬ μ•„λž˜μ™€ 같은 λ°©μ‹μœΌλ‘œ ν‘œν˜„ν•œλ‹€.\n", "\n", "$((\\lambda x.x^2)~3)$\n", "\n", "μˆ˜ν•™μ—μ„œλ„ κ·Έλ ‡λ“― λžŒλ‹€κ³„μ‚°λ²•μ—μ„œλ„ μ–΄λ–€ ν•¨μˆ˜κ°€ λ‹€λ₯Έ ν•¨μˆ˜λ₯Ό λ°›μ•„ 또 λ‹€λ₯Έ ν•¨μˆ˜λ₯Ό λ§Œλ“€μ–΄λ‚Ό 수 μžˆλ‹€.\n", "κ°€μž₯ λŒ€ν‘œμ μΈ 예둜 'λ―ΈλΆ„'μ΄λΌλŠ” κ°œλ…μ„ ν•¨μˆ˜λ₯Ό λ°›μ•„ ν•¨μˆ˜λ₯Ό λŒλ €μ£ΌλŠ” ν•¨μˆ˜λ‘œ 이해할 μˆ˜λ„ μžˆλ‹€.\n", "\n", "$((λ―ΈλΆ„~(\\lambda x.x^2))~3) \\longrightarrow\\cdots\\longrightarrow ((\\lambda x.\\,2\\times x)~3) \\longrightarrow 2\\times 3 \\longrightarrow 6$\n", "\n", "λ¬Όλ‘  μˆœμˆ˜ν•œ λžŒλ‹€κ³„μ‚°λ²•μ—λŠ” λ―ΈλΆ„μ΄λ‚˜, 제곱, κ³±ν•˜κΈ°, λ“±μ˜ κ°œλ…μ„ 기본적으둜 μ œκ³΅ν•˜μ§€λŠ” μ•ŠμœΌλ©° 심지어 μžμ—°μˆ˜λ„ κΈ°λ³Έ κ΅¬μ„±μš”μ†Œλ‘œ μ œκ³΅λ˜μ§€ μ•ŠλŠ”λ‹€. μœ„μ— μ˜ˆμ œλŠ” κ°œλ…μ μΈ 이해λ₯Ό 돕기 μœ„ν•œ μ„€λͺ…이닀. 참고둜 Alonzo Church의 λžŒλ‹€κ³„μ‚°λ²•μ€ Alan Turing의 νŠœλ§λ¨Έμ‹ κ³Ό λ§ˆμ°¬κ°€μ§€λ‘œ 괴델이 \"μˆ˜ν•™λͺ…μ œ μžλ™νŒλ³„ 문제\"κ°€ ν•΄κ²° λΆˆκ°€λŠ₯함을 증λͺ…ν•œ λΆˆμ™„μ „μ„± 정리λ₯Ό κ·Έλ“€ λ‚˜λ¦„μ˜ λ°©μ‹μœΌλ‘œ 쒀더 μ§μ ‘μ μœΌλ‘œ κ°„λž΅ν•˜κ²Œ 증λͺ…ν•˜κΈ° μœ„ν•œ 이둠적 도ꡬ ν˜Ήμ€ μ†Œν’ˆμœΌλ‘œ λ§Œλ“€μ–΄μ§„ 것이닀. κ°€μ •ν•˜λŠ” 것이 μ•„λ‹ˆλΌ ν•˜μ§€λ§Œ 이후 이런 μ†Œν’ˆλ“€μ˜ 이둠적 계산λŠ₯λ ₯이 λ™μΌν•˜λ‹€λŠ” 것이 λ°ν˜€μ§€λ©΄μ„œ μ˜€λŠ˜λ‚  μš°λ¦¬κ°€ μ΄ν•΄ν•˜λŠ” μ»΄ν“¨ν„°λ‘œ ν•  수 μžˆλŠ” λͺ¨λ“  κ³„μ‚°μ˜ 이둠적 λ²”μœ„λ₯Ό λ°œκ²¬ν•œ κ²ƒμœΌλ‘œ λ°›μ•„λ“€μ—¬μ§€κ³  μžˆλŠ”λ° 이λ₯Ό 처치-튜링 λ…Όμ œ(Church-Turing thesis)라고 ν•œλ‹€. 이와 κ΄€λ ¨ν•œ 역사적 λ°°κ²½ 및 쒀더 μžμ„Έν•œ λ‚΄μš©μ΄ κΆκΈˆν•œ μ‚¬λžŒλ“€μ€ λ‹€μŒ μ˜¨λΌμΈμ— 곡개된 [컴퓨터과학이 μ—¬λŠ” 세계](https://www.youtube.com/watch?v=HTWSPoDLmHI&list=PL0Nf1KJu6Ui7yoc9RQ2TiiYL9Z0MKoggH) κ°•μ˜ μ‹œλ¦¬μ¦ˆμ˜ 1.4, 1.5, 1.6 λ‚΄μš© μ˜μƒ 등이 μ°Έκ³ κ°€ 될 것이닀." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "-- λ³€μˆ˜ 이름은 λ¬Έμžμ—΄ λ‚˜νƒ€λ‚Έλ‹€\n", "type Nm = String\n", "\n", "-- λžŒλ‹€μ‹ 문법 ꡬ쑰\n", "data Tm = Var Nm -- x\n", " | Lam Nm Tm -- (Ξ»x.e)\n", " | App Tm Tm -- (e1 e2)\n", " deriving (Show, Eq)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "-- λžŒλ‹€μ‹μ„ λ³΄κΈ°μ’‹κ²Œ λ¬Έμžμ—΄λ‘œ λ³€ν™˜ν•΄μ£ΌλŠ” ν•¨μˆ˜\n", "ppTm (Var x) = x\n", "ppTm (Lam x e) = \"\\\\\" ++ x ++ \" -> \" ++ ppTm e\n", "ppTm (App e1 e2) = pp1 e1 ++ \" \" ++ pp2 e2\n", " where\n", " pp1 e@(Lam{}) = paren (ppTm e)\n", " pp1 e = ppTm e\n", " pp2 e@(Var{}) = ppTm e\n", " pp2 e = paren (ppTm e)\n", "\n", "paren s = \"(\" ++ s ++ \")\"\n", "brack s = \"[\" ++ s ++ \"]\"\n", "latex s = \"$\" ++ s ++ \"$\"\n", "\n", "-- λžŒλ‹€μ‹μ„ λ³΄κΈ°μ’‹κ²Œ TeX μ½”λ“œλ‘œ λ³€ν™˜ν•΄μ£ΌλŠ” ν•¨μˆ˜\n", "texTm (Var x) = x\n", "texTm (Lam x e) = \"\\\\lambda \" ++ x ++ \".\" ++ texTm e\n", "texTm (App e1 e2) = tex1 e1 ++ \"~\" ++ tex2 e2\n", " where\n", " tex1 e@(Lam{}) = paren (texTm e)\n", " tex1 t = texTm t\n", " tex2 s@(Var{}) = texTm s\n", " tex2 s = paren (texTm s)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "idTm = Lam \"x\" (Var \"x\")\n", "ttTm = Lam \"x\" (Lam \"y\" (Var \"x\")) \n", "ffTm = Lam \"x\" (Lam \"y\" (Var \"y\")) " ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\\x -> x" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "\\x -> \\y -> x" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "\\x -> \\y -> y" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "putStr $ ppTm idTm\n", "putStr $ ppTm ttTm\n", "putStr $ ppTm ffTm" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "$\\lambda x.x$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$\\lambda x.\\lambda y.x$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$\\lambda x.\\lambda y.y$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$x~y~z$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$x~(y~z)$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$(\\lambda x.\\lambda y.y)~(\\lambda x.x)~(\\lambda x.\\lambda y.x)$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$(\\lambda x.\\lambda y.y)~((\\lambda x.x)~(\\lambda x.\\lambda y.x))$" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import IHaskell.Display\n", "\n", "html . latex $ texTm idTm\n", "html . latex $ texTm ttTm\n", "html . latex $ texTm ffTm\n", "html . latex $ texTm (App (App (Var \"x\") (Var \"y\")) (Var \"z\"))\n", "html . latex $ texTm (App (Var \"x\") (App (Var \"y\") (Var \"z\")))\n", "html . latex $ texTm (App (App ffTm idTm) ttTm)\n", "html . latex $ texTm (App ffTm (App idTm ttTm))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 뢀뢄식(sub-expression)\n", "λžŒλ‹€μ‹μ˜ 뢀뢄식은 κ·Έ μ‹μ˜ μΌλΆ€λ‘œ λ‚˜νƒ€λ‚˜λŠ” λžŒλ‹€μ‹μ΄λ‹€. 전체 식 μžμ²΄λ„ 자기 μžμ‹ μ˜ 뢀뢄식이라고 ν•˜μž.\n", "\n", "ν•˜μŠ€μΌˆ 데이타 νƒ€μž… `Tm`으둜 ν‘œν˜„λœ μ–΄λ–€ λžŒλ‹€μ‹μ˜ 뢀뢄식을 λͺ¨λ‘ λ‚˜μ—΄ν•˜λŠ” 리슀트λ₯Ό κ΅¬ν•˜λŠ” ν•¨μˆ˜λ₯Ό λ‹€μŒκ³Ό 같이 μž‘μ„±ν•  수 μžˆλ‹€." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[2,3,4,7,8]" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "[2,3,4] ++ [7,8]" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "subTm :: Tm -> [Tm]\n", "subTm (Var x) = [(Var x)] -- (Var x) : []\n", "subTm (Lam x e1) = (Lam x e1) : subTm e1\n", "subTm (App e1 e2) = (App e1 e2) : subTm e1 ++ subTm e2" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/html": [ "$(\\lambda x.x)~(\\lambda y.y)$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "[App (Lam \"x\" (Var \"x\")) (Lam \"y\" (Var \"y\")),Lam \"x\" (Var \"x\"),Var \"x\",Lam \"y\" (Var \"y\"),Var \"y\"]" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$(\\lambda x.x)~(\\lambda y.y)$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$\\lambda x.x$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$x$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$\\lambda y.y$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$y$" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "e = App (Lam \"x\" (Var \"x\")) (Lam \"y\" (Var \"y\"))\n", "\n", "html . latex . texTm $ e\n", "\n", "subTm e\n", "\n", "map (html . latex . texTm) (subTm e)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "νŒ¨ν„΄λ§€μΉ­μ—μ„œ λΆ€λΆ„λ³„λ‘œ 이름을 λΆ™μž„κ³Ό λ™μ‹œμ— ꡬ쑰 전체에도 이름을 λΆ™μ—¬μ£Όλ €λ©΄ `@`을 ν™œμš©ν•œλ‹€.\n", "μ˜ˆμ»¨λŒ€ μœ„μ˜ `subTm`κ³Ό 같은 ν•¨μˆ˜λ₯Ό λ‹€μŒκ³Ό `@`νŒ¨ν„΄μ„ ν™œμš©ν•˜λ©΄ 더 κ°„κ²°ν•˜κ²Œ μ •μ˜λ˜λ©°,\n", "μ»΄νŒŒμΌλŸ¬κ°€ ꡬ쑰 전체λ₯Ό ν•¨μˆ˜ κ²°κ³Όμ—μ„œ κ·ΈλŒ€λ‘œ μ°Έμ‘°ν•  수 μžˆλŠ” μΆ”κ°€ 정보가 돌 수 μžˆμœΌλ―€λ‘œ\n", "컴파일된 μ½”λ“œμ˜ μ„±λŠ₯이 κ°œμ„ λ  κ°€λŠ₯성도 μžˆλ‹€." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "subTm' :: Tm -> [Tm]\n", "subTm' e@(Var _) = [e]\n", "subTm' e@(Lam x e1) = e : subTm e1\n", "subTm' e@(App e1 e2) = e : subTm e1 ++ subTm e2" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[App (Lam \"x\" (Var \"x\")) (Lam \"y\" (Var \"y\")),Lam \"x\" (Var \"x\"),Var \"x\",Lam \"y\" (Var \"y\"),Var \"y\"]" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$(\\lambda x.x)~(\\lambda y.y)$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$\\lambda x.x$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$x$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$\\lambda y.y$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$y$" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "e = App (Lam \"x\" (Var \"x\")) (Lam \"y\" (Var \"y\"))\n", "\n", "subTm' e\n", "\n", "map (html . latex . texTm) (subTm' e)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## μ£ΌλŠ”μ‹(redex)\n", "λžŒλ‹€κ³„μ‚°λ²•μ˜ μ‹€ν–‰μ˜λ―ΈλŠ” κ·Έ λ¬Έλ²•λ§ŒνΌμ΄λ‚˜ 맀우 λ‹¨μˆœν•˜λ‹€.\n", "ν•¨μˆ˜μ •μ˜μ‹ $(\\lambda x.e)$λ₯Ό 인자 $e_2$에 μ μš©ν•œ\n", "ν•¨μˆ˜μ μš©μ‹ $((\\lambda x.e)~e_2)$λŠ” κ³§λ°”λ‘œ 쀄일 수 μžˆλŠ”\n", "μ£ΌλŠ”μ‹(redex)이며 그것을 ν•œ 걸음 쀄인 κ²°κ³ΌλŠ”\n", "$e$에 λ‚˜νƒ€λ‚˜λŠ” $x$λ₯Ό $e_2$둜 μΉ˜ν™˜ν•œ 식,\n", "즉 $x$의 μžλ¦¬μ— $x$λŒ€μ‹  $e_2$둜 λΌμ›Œλ„£μ€ 식이 λœλ‹€.\n", "달리 λ§ν•˜μ§€λ©΄ μ£ΌλŠ”μ‹μ΄λž€ μ¦‰μ‹œ ν•¨μˆ˜ ν˜ΈμΆœμ„ ν•  수 μžˆλŠ” ν˜•νƒœμ˜ ν•¨μˆ˜μ μš©μ‹μ„ λ§ν•˜λŠ” 것이닀.\n", "μ™œλƒν•˜λ©΄ μ¦‰μ‹œ ν•¨μˆ˜ 호좜이 κ°€λŠ₯ν•˜λ €λ©΄ μ™Όμͺ½μ— μ˜€λŠ” ν•¨μˆ˜ 뢀뢄이 λžŒλ‹€λ‘œ μ‹œμž‘ν•˜λŠ” ν•¨μˆ˜μ •μ˜μ‹μ΄μ–΄μ•Ό ν•˜λ‹ˆκΉŒ.\n", "μ΄λŸ¬ν•œ 계산 κ·œμΉ™μ„ $\\beta$-쀄이기($\\beta$-reduction)이라고 ν•˜λ©°\n", "μ•„λž˜μ™€ 같이 λ‚˜νƒ€λ‚Έλ‹€. 참고둜 μ€„μ΄λŠ” 방법이 ν•œ κ°€μ§€κ°€ μ•„λ‹ˆλΌ μ—¬λŸ¬ κ°€μ§€ κ·œμΉ™μ΄ ν¬ν•¨λœ\n", "λžŒλ‹€κ³„μ‚°λ²•μ˜ 변이듀도 κ°€λŠ₯ν•œλ° 그런 경우 νŠΉμ • κ·œμΉ™μ— 따라 μ£ΌλŠ”μ‹μž„μ„ ν‘œν˜„ν•˜κΈ° μœ„ν•΄\n", "$\\beta$-μ£ΌλŠ”μ‹($\\beta$-redex)이라고 μ€„μ΄λŠ” κ·œμΉ™μ˜ 이름을 μ•žμ— λΆ™μ—¬μ„œ λ§ν•˜κΈ°λ„ ν•œλ‹€.\n", "\n", "$((\\lambda x. e)~e_2) \\longrightarrow \\{x\\mapsto e_2\\}e$\n", "\n", "μ—¬κΈ°μ—μ„œ $\\{x\\mapsto e_2\\}e$λŠ” λ°”λ‘œ $e$μ—μ„œ $x$λ₯Ό $e_2$둜 μΉ˜ν™˜ν•œ 식을 μ˜λ―Έν•˜λŠ” ν‘œκΈ°λ²•μ΄λ‹€.\n", "μ˜ˆμ»¨λŒ€ $\\big(\\big(\\lambda x.(\\lambda y.(y~x)~x)\\big)~z\\big)$λ₯Ό\n", "쀄이면 $\\{x\\mapsto z\\}(\\lambda y.(y~x)~x)$ κ·ΈλŸ¬λ‹ˆκΉŒ $(\\lambda y.(y~z)~z)$κ°€ λœλ‹€.\n", "\n", "참고둜 μœ„μ˜ $\\beta$-쀄이기 κ·œμΉ™μ„ ν•΅μ‹¬μœΌλ‘œ ν•˜λ˜, μ–΄λ–€ 식이 κ·Έ μžμ²΄λ‘œλŠ” $\\beta$-쀄이기 κ·œμΉ™μ˜\n", "적용 λŒ€μƒμ΄ μ•„λ‹ˆλ”λΌλ„ κ·œμΉ™μ΄ μ μš©λ˜λŠ” 뢀뢄을 μ°Ύμ•„ κ·Έ λΆ€λΆ„μ˜ 식에 $\\beta$-쀄이기λ₯Ό μ μš©ν•˜λŠ”\n", "κ·œμΉ™λ“€μ„ μΆ”κ°€λ‘œ μ •μ˜ν•  수 μžˆλ‹€. μ˜ˆμ»¨λŒ€, $\\big(\\big((\\lambda x.x)~(\\lambda y.y)\\big)~(\\lambda z.z)\\big)$λŠ”\n", "κ·Έ μžμ²΄λ‘œλŠ” 식 전체에 $\\beta$-쀄이기 κ·œμΉ™μ„ μ μš©ν•  수 μ—†μ§€λ§Œ\n", "κ·Έ 뢀뢄식인 $\\big((\\lambda x.x)~(\\lambda y.y)\\big)$μ—λŠ” $\\beta$-쀄이기 κ·œμΉ™μ„ μ μš©ν•  수 μžˆλ‹€.\n", "사싀 뢀뢄식에 $\\beta$-쀄이기λ₯Ό μ–΄λ–»κ²Œ μ μš©ν• μ§€λŠ” μ—¬λŸ¬ κ°€μ§€\n", "방법 ν˜Ήμ€ μ „λž΅μ΄ κ°€λŠ₯ν•œλ° μ§€κΈˆμ€ 일단 μ λ‹Ήνžˆ 아무 κ³³μ—λ‚˜ μ μš©ν•œλ‹€κ³  ν•˜κ³  λ„˜μ–΄κ°€κΈ°λ‘œ ν•˜κ³  이후에\n", "λ‹€μ‹œ 이에 λŒ€ν•΄ 생각해 보겠닀.\n", "\n", "ν•˜μŠ€μΌˆ 데이타 νƒ€μž… `Tm`으둜 ν‘œν˜„λœ μ–΄λ–€ λžŒλ‹€μ‹μ΄\n", "κ·Έ 자체둜 $\\beta$-쀄이기 κ·œμΉ™μ„ λ°”λ‘œ μ μš©ν•  수 μžˆλŠ” μ£ΌλŠ”μ‹(redex)인지\n", "κ²€μ‚¬ν•˜λŠ” ν•¨μˆ˜λ₯Ό λ‹€μŒκ³Ό 같이 μž‘μ„±ν•  수 μžˆλ‹€." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "isRedEx :: Tm -> Bool\n", "isRedEx (App (Lam{}) _) = True\n", "isRedEx _ = False" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/html": [ "$\\lambda x.x$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "False" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$(\\lambda x.x)~(\\lambda x.x)$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "True" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$\\lambda x.(\\lambda x.x)~(\\lambda x.x)$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "False" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "e1 = idTm\n", "e2 = App idTm idTm\n", "e3 = (Lam \"x\" e2)\n", "\n", "html . latex $ texTm e1\n", "isRedEx e1\n", "html . latex $ texTm e2\n", "isRedEx e2\n", "html . latex $ texTm e3\n", "isRedEx e3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "μ£Όμ–΄μ§„ 식 μžμ²΄λ‘œλŠ” μ£ΌλŠ”μ‹(redex)이 μ•„λ‹ˆλ”λΌλ„ μ–΄λ–€ λΆ€λΆ„μ˜ 뢀뢄식에 μ£ΌλŠ”μ‹μ„ ν¬ν•¨ν•˜κ³  μžˆμ„ μˆ˜λ„ μžˆλ‹€.\n", "κ·Έ 자체둜 μ£ΌλŠ” 식인 경우 뿐만 μ•„λ‹ˆλΌ λΆ€λΆ„μ‹μœΌλ‘œ μ£ΌλŠ”μ‹μ„ ν¬ν•¨ν•˜λŠ” μ‹μΈμ§€κΉŒμ§€ κ²€μ‚¬ν•˜λŠ” `hasRedEx` ν•¨μˆ˜λ₯Ό\n", "λ‹€μŒκ³Ό 같이 μž‘μ„±ν•  수 μžˆλ‹€." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "hasRedEx :: Tm -> Bool\n", "hasRedEx (Var _) = False\n", "hasRedEx (Lam _ e1) = hasRedEx e1\n", "hasRedEx e@(App e1 e2) = isRedEx e || hasRedEx e1 || hasRedEx e2" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/html": [ "$\\lambda x.x$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "False" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$(\\lambda x.x)~(\\lambda x.x)$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "True" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$\\lambda x.(\\lambda x.x)~(\\lambda x.x)$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "True" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "e1 = idTm\n", "e2 = App idTm idTm\n", "e3 = (Lam \"x\" e2)\n", "\n", "html . latex $ texTm e1\n", "hasRedEx e1\n", "html . latex $ texTm e2\n", "hasRedEx e2\n", "html . latex $ texTm e3\n", "hasRedEx e3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "참고둜 μœ„μ™€ 같은 일을 ν•˜λŠ” λ‹€λ₯Έ λ°©λ²•μœΌλ‘œλ„ μ •μ˜ν•  수 μžˆλ‹€.\n", "μ•žμ„œ μ •μ˜ν•œ `subTm` ν•¨μˆ˜λ‘œ 뢀뢄식을 λͺ¨λ‘ λ‚˜μ—΄ν•˜μ—¬\n", "κ·Έ 쀑 ν•˜λ‚˜λΌλ„ μ£ΌλŠ” 식이 μžˆλŠ”μ§€ κ²€μ‚¬ν•˜λŠ” `isRedEx` ν•¨μˆ˜μ™€ ν•¨κ»˜\n", "ν‘œμ€€λΌμ΄λΈŒλŸ¬λ¦¬ κ³ μ°¨ν•¨μˆ˜ `any`λ₯Ό ν™œμš©ν•˜λ©΄ μ•Œμ•„λ³Ό 수 μžˆμœΌλ―€λ‘œ\n", "λ˜‘κ°™μ€ 일을 ν•˜λŠ” ν•¨μˆ˜λ₯Ό λ‹€μŒκ³Ό 같이 μ •μ˜ν•  μˆ˜λ„ μžˆλ‹€." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "True" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "even 3\n", "even 4" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "True" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "any even [1,3,5,7,9]\n", "any even [1,3,4,7,9]" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "hasRedEx' = any isRedEx . subTm" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/html": [ "$\\lambda x.x$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "False" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$(\\lambda x.x)~(\\lambda x.x)$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "True" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$\\lambda x.(\\lambda x.x)~(\\lambda x.x)$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "True" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "e1 = idTm\n", "e2 = App idTm idTm\n", "e3 = (Lam \"x\" e2)\n", "\n", "html . latex $ texTm e1\n", "hasRedEx' e1\n", "html . latex $ texTm e2\n", "hasRedEx' e2\n", "html . latex $ texTm e3\n", "hasRedEx' e3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "----" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "-- texTm을 적절히 λ³€κ²½ν•˜μ—¬ ν•¨μˆ˜μ μš©μ‹ (e1 e2)μ—μ„œ\n", "-- ν•¨μˆ˜ 뢀뢄인 e1에 λΉ¨κ°• 인자 뢀뢄인 e2에 νŒŒλž‘ μ‚¬κ°ν˜• ν…Œλ‘λ¦¬ μΆ”κ°€\n", "texTmColor (Var x) = x\n", "texTmColor (Lam x e) = \"\\\\lambda \" ++ x ++ \".\" ++ texTmColor e\n", "texTmColor (App e1 e2) = box1(tex1 e1) ++ \"~\" ++ box2(tex2 e2)\n", " where\n", " tex1 e@(Lam{}) = paren (texTmColor e)\n", " tex1 t = texTmColor t\n", " tex2 s@(Var{}) = texTmColor s\n", " tex2 s = paren (texTmColor s)\n", " box1 = red . boxed . black\n", " box2 = blue . boxed . black\n", "\n", "color c s = \"\\\\color{\"++c++\"}{\"++s++\"}\"\n", "boxed s = \"\\\\boxed{\"++s++\"}\"\n", "\n", "black = color \"black\"\n", "red = color \"red\"\n", "blue = color \"blue\"" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/html": [ "$(\\lambda f.(\\lambda x.x)~((\\lambda x.x)~(f~f)))~((\\lambda x.x)~(\\lambda x.x))$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "\\color{red}{\\boxed{\\color{black}{(\\lambda f.\\color{red}{\\boxed{\\color{black}{(\\lambda x.x)}}}~\\color{blue}{\\boxed{\\color{black}{(\\color{red}{\\boxed{\\color{black}{(\\lambda x.x)}}}~\\color{blue}{\\boxed{\\color{black}{(\\color{red}{\\boxed{\\color{black}{f}}}~\\color{blue}{\\boxed{\\color{black}{f}}})}}})}}})}}}~\\color{blue}{\\boxed{\\color{black}{(\\color{red}{\\boxed{\\color{black}{(\\lambda x.x)}}}~\\color{blue}{\\boxed{\\color{black}{(\\lambda x.x)}}})}}}" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$\\color{red}{\\boxed{\\color{black}{(\\lambda f.\\color{red}{\\boxed{\\color{black}{(\\lambda x.x)}}}~\\color{blue}{\\boxed{\\color{black}{(\\color{red}{\\boxed{\\color{black}{(\\lambda x.x)}}}~\\color{blue}{\\boxed{\\color{black}{(\\color{red}{\\boxed{\\color{black}{f}}}~\\color{blue}{\\boxed{\\color{black}{f}}})}}})}}})}}}~\\color{blue}{\\boxed{\\color{black}{(\\color{red}{\\boxed{\\color{black}{(\\lambda x.x)}}}~\\color{blue}{\\boxed{\\color{black}{(\\lambda x.x)}}})}}}$" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "e1 = Lam \"f\" (App idTm (App idTm (Var \"f\" `App` Var \"f\"))) `App` App idTm idTm\n", "html . latex $ texTm e1\n", "putStr $ texTmColor e1\n", "html . latex $ texTmColor e1" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "-- texTmRedEx :: Tm -> String\n", "-- texTm을 적절히 λ³€κ²½ν•˜μ—¬ ν•¨μˆ˜μ μš©μ‹ (e1 e2)μ—μ„œ\n", "-- ν•¨μˆ˜ 뢀뢄인 e1에 λΉ¨κ°• 인자 뢀뢄인 e2에 νŒŒλž‘ μ‚¬κ°ν˜• ν…Œλ‘λ¦¬ μΆ”κ°€\n", "texTmRedEx (Var x) = x\n", "texTmRedEx (Lam x e) = \"\\\\lambda \" ++ x ++ \".\" ++ texTmRedEx e\n", "texTmRedEx e@(App e1 e2) =\n", " if isRedEx e then box1(tex1 e1) ++ \"~\" ++ box2(tex2 e2)\n", " else tex1 e1 ++ \"~\" ++ tex2 e2\n", " where\n", " tex1 e@(Lam{}) = paren (texTmRedEx e)\n", " tex1 t = texTmRedEx t\n", " tex2 s@(Var{}) = texTmRedEx s\n", " tex2 s = paren (texTmRedEx s)\n", " box1 = red . boxed . black\n", " box2 = blue . boxed . black" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\\color{red}{\\boxed{\\color{black}{(\\lambda f.\\color{red}{\\boxed{\\color{black}{(\\lambda x.x)}}}~\\color{blue}{\\boxed{\\color{black}{(\\color{red}{\\boxed{\\color{black}{(\\lambda x.x)}}}~\\color{blue}{\\boxed{\\color{black}{(f~f)}}})}}})}}}~\\color{blue}{\\boxed{\\color{black}{(\\color{red}{\\boxed{\\color{black}{(\\lambda x.x)}}}~\\color{blue}{\\boxed{\\color{black}{(\\lambda x.x)}}})}}}" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$\\color{red}{\\boxed{\\color{black}{(\\lambda f.\\color{red}{\\boxed{\\color{black}{(\\lambda x.x)}}}~\\color{blue}{\\boxed{\\color{black}{(\\color{red}{\\boxed{\\color{black}{(\\lambda x.x)}}}~\\color{blue}{\\boxed{\\color{black}{(f~f)}}})}}})}}}~\\color{blue}{\\boxed{\\color{black}{(\\color{red}{\\boxed{\\color{black}{(\\lambda x.x)}}}~\\color{blue}{\\boxed{\\color{black}{(\\lambda x.x)}}})}}}$" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "e1 = Lam \"f\" (App idTm (App idTm (Var \"f\" `App` Var \"f\"))) `App` App idTm idTm\n", "putStr $ texTmRedEx e1\n", "html. latex $ texTmRedEx e1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "----" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ν‘œμ€€ν˜•(normal form)\n", "\n", "ν‘œμ€€ν˜•μ€ κ·œμΉ™μ— 따라 더 이상 쀄일 수 μžˆλŠ” 뢀뢄식을 ν¬ν•¨ν•˜μ§€ μ•ŠλŠ” ν˜•νƒœμ˜ λžŒλ‹€μ‹μ„ λ§ν•œλ‹€.\n", "ꡬ체적으둜 $\\beta$-μ€„μ΄κΈ°λ‘œ 더 이상 쀄일 수 μžˆλŠ” 뢀뢄식이 μ „ν˜€ ν¬ν•¨ν•˜μ§€ μ•ŠλŠ” λžŒλ‹€μ‹μ„ $\\beta$-ν‘œμ€€ν˜•μ΄λΌ μΌμ»«λŠ”λ‹€.\n", "\n", "μ£Όμ–΄μ§„ λžŒλ‹€μ‹ $e$에 $\\beta$-쀄이기λ₯Ό 반볡적으둜 μ μš©ν•΄ 얻을 수 μžˆλŠ” $\\beta$-ν‘œμ€€ν˜•μ„\n", "$e$의 $\\beta$-ν‘œμ€€ν˜•μ΄λΌ λ§ν•˜λŠ”λ°, νƒ€μž…μ—†λŠ” λžŒλ‹€κ³„μ‚°λ²•μ—μ„œλŠ”\n", "μ£Όμ–΄μ§„ λžŒλ‹€μ‹μ˜ $\\beta$-ν‘œμ€€ν˜•μ΄ μ‘΄μž¬ν•œλ‹€λ©΄ μœ μΌν•˜λ‹€λŠ”\n", "**처치-λ‘œμ„œ 정리(Church-Rosser theorem)**κ°€ μ„±λ¦½νžŒλ‹€.\n", "\n", "λžŒλ‹€κ³„μ‚°λ²•μ˜ 처치-λ‘œμ„œ 정리λ₯Ό 직접 μ„€λͺ…ν•˜κΈ°λ³΄λ‹€λŠ”\n", "μš°μ„  μ§κ΄€μ μœΌλ‘œ 처치-λ‘œμ„œ 정리가 μ–΄λ–€ μ„±μ§ˆμ„ μ˜λ―Έν•˜λŠ”μ§€ λ§μ…ˆμ‹μ„ 톡해 κ°„λ‹¨νžˆ κ°œλ…λ§Œ μ•Œμ•„λ³΄μž.\n", " \n", "예λ₯Ό λ“€μ–΄ (1 + 2) + (4 + 5) λΌλŠ” λ§μ…ˆμ‹μ΄ μžˆλ‹€λ©΄ μ–΄λ–€ λ§μ…ˆμ„ λ¨Όμ € ν•˜λ“  관계없이 항상 같은 결과값을 μ–»λŠ”λ‹€.\n", "즉 λ§μ…ˆμ‹μ—μ„œλŠ” λ§μ…ˆμ„ μ€„μ—¬λ‚˜κ°€λŠ” 것에 λŒ€ν•œ 처치-λ‘œμ„œ μ •λ¦¬μ˜ μ„±μ§ˆμ΄ μ„±λ¦½ν•œλ‹€κ³  말할 수 μžˆλ‹€.\n", "\n", "$(1 + 2) + (4 + 5) ~\\longrightarrow~ 3 + (4 + 5) ~\\longrightarrow~ 3 + 9 ~\\longrightarrow~ 12$\n", "\n", "$(1 + 2) + (4 + 5) ~\\longrightarrow~ (1 + 2) + 9 ~\\longrightarrow~ 3 + 9 ~\\longrightarrow~ 12$\n", "\n", "ν•˜μ§€λ§Œ νƒ€μž…μ—†λŠ” λžŒλ‹€κ³„μ‚°λ²•μ˜ 경우 계산이 일반적으둜 항상 λλ‚œλ‹€λŠ” 보μž₯이 μ—†λ‹€.\n", "즉 μ–΄λ–€ λžŒλ‹€μ‹μ€ ν‘œμ€€ν˜•μ΄ μ•„μ˜ˆ μ‘΄μž¬ν•˜μ§€ μ•Šμ„ μˆ˜λ„ 있으며\n", "ν‘œμ€€ν˜•μ΄ μ‘΄μž¬ν•˜λ”λΌλ„ μ–΄λ–€ 쀄일식을 λ¨Όμ € κ³„μ‚°ν•˜λŠ”κ°€μ— 따라\n", "계산이 끝날 μˆ˜λ„ 있고 λλ‚˜μ§€ μ•Šμ„ μˆ˜λ„ μžˆλ‹€. κ·Έλž˜μ„œ νƒ€μž…μ—†λŠ”\n", "λžŒλ‹€κ³„μ‚°λ²•μ—μ„œμ˜ 처치-λ‘œμ„œ μ •λ¦¬λŠ” ν‘œμ€€ν˜•μ΄ μ‘΄μž¬ν•˜λŠ” μ‹μ˜ 경우\n", "ν‘œμ€€ν˜•μ— 도달할 수 μžˆλŠ” λͺ¨λ“  계산 경둜 끝에 μžˆλŠ” ν‘œμ€€ν˜•μ΄ λͺ¨λ‘ \"κ°™λ‹€\"λŠ” μ˜λ―Έμ΄λ‹€.\n", "\n", "참고둜 ν‘œμ€€ν˜•μ΄ μ—†λŠ” λλ‚˜μ§€ μ•ŠλŠ” 계산을 ν•˜λŠ” λŒ€ν‘œμ μΈ μ˜ˆκ°€ λ°”λ‘œ λ‹€μŒκ³Ό 같은 λžŒλ‹€μ‹μ΄λ‹€.\n", "\n", "$\n", "\\big((\\lambda x.x~x)~(\\lambda x.x~x)\\big)\n", "\\longrightarrow\n", "\\big((\\lambda x.x~x)~(\\lambda x.x~x)\\big)\n", "\\longrightarrow\n", "~~\\cdots$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## $\\alpha$-λ³€ν™˜ ($\\alpha$-conversion), $\\alpha$-λ™μΉ˜ ($\\alpha$-equivalence)\n", "\n", "잠깐, 근데 \"κ°™λ‹€\"λŠ” 게 무엇인지 μš°λ¦¬κ°€ 아직 μ •ν™•νžˆ μ •μ˜ν•˜μ§€ μ•Šμ•˜λ‹€.\n", "\n", "일단 ν™•μ‹€ν•œ 것은 κΈ€μž ν•˜λ‚˜λ„ 틀리지 μ•Šκ³  λ˜‘κ°™μœΌλ©΄ λΆ„λͺ…νžˆ 같은 것이닀.\n", "ν•˜μ§€λ§Œ 이것은 λ„ˆλ¬΄λ‚˜ ν˜‘μ†Œν•œ κ°™μŒμ˜ μ •μ˜λ‹€.\n", "μ™œλƒν•˜λ©΄ $(\\lambda x.x)$와 $(\\lambda y.y)$의 경우\n", "비둝 κΈ€μž ν•˜λ‚˜ν•˜λ‚˜λ₯Ό λΉ„κ΅ν•˜λ©΄ λ‹€λ₯Έ 점이 μžˆκΈ°λŠ” ν•˜μ§€λ§Œ\n", "λΆ„λͺ…νžˆ λ˜‘κ°™μ€ 식이라고 λ³Ό 수 있기 λ•Œλ¬Έμ΄λ‹€.\n", "$(\\lambda x.x)$μ—μ„œ ν•¨μˆ˜ 인자의 이름을 $x$λŒ€μ‹  $y$둜 λ°”κΎΌ ν•¨μˆ˜κ°€ $(\\lambda y.y)$이닀.\n", "μ΄λ ‡κ²Œ ν•¨μˆ˜ 인자의 이름을 μΌκ΄„μ μœΌλ‘œ λ°”κΏ”λŠ” 것을 $\\alpha$-λ³€ν™˜μ΄λΌκ³  ν•˜λ©°,\n", "ν•¨μˆ˜ 인자 μ΄λ¦„λ§Œ λ°”κΏ”λ‚˜κ°€λ©΄ λ˜‘κ°™μ•„μ§€λŠ” 관계에 μžˆλŠ” λžŒλ‹€μ‹λ“€μ„ $\\alpha$-λ™μΉ˜ 관계에 μžˆλ‹€κ³  ν•œλ‹€.\n", "\n", "## $\\beta$-λ™μΉ˜ ($\\beta$-equivalence)\n", "$((\\lambda x.x)~(\\lambda y.y))$와 $((\\lambda y.(\\lambda x.x))~z)$λŠ” $\\alpha$-λ™μΉ˜κ°€ μ•„λ‹ˆλ‹€.\n", "ν•˜μ§€λ§Œ 이λ₯Ό $\\beta$-μ€„μ΄κΈ°λ‘œ ν•œλ‹¨κ³„λ§Œ κ³„μ‚°ν•˜λ©΄ 계산 결과둜 λ‚˜μ˜€λŠ” 식듀이 $\\alpha$-λ™μΉ˜μž„μ„ μ•Œ 수 μžˆλ‹€.\n", "\n", "$((\\lambda x.x)~(\\lambda y.y)) \\longrightarrow (\\lambda y.y)$\n", "\n", "$((\\lambda y.(\\lambda x.x))~z) \\longrightarrow (\\lambda x.x)$\n", "\n", "\n", "이와 같이 $\\beta$-쀄이기λ₯Ό (μΌλ°˜μ μœΌλ‘œλŠ” ν•œ 걸음만 μ•„λ‹ˆλΌ μ—¬λŸ¬ 걸음으둜) μ μš©ν•΄μ„œ κ°™μ•„μ§€λŠ”\n", "관계λ₯Ό $\\beta$-λ™μΉ˜λΌκ³  ν•œλ‹€. λ§μ…ˆμ‹μœΌλ‘œ λΉ„μœ ν•˜μžλ©΄ ((3+4)+5)와 (2+(5+6))처럼 κ΅¬μ‘°λ‚˜ μƒκΉ€μƒˆκ°€\n", "μ„€λ Ή λ‹€λ₯΄λ”라도 계산 κ²°κ³Όκ°€ 같은 관계에 ν•΄λ‹Ήν•œλ‹€. ν‘œμ€€ν˜•μ΄ μžˆλŠ” λžŒλ‹€μ‹λΌλ¦¬ λΉ„κ΅ν•˜λŠ” 경우라면 처치-λ‘œμ„œ μ •λ¦¬μ˜ μ„±μ§ˆμ—\n", "μ˜κ±°ν•΄ μ„œλ‘œμ˜ ν‘œμ€€ν˜•μ„ ꡬ해 같은지 μ•Œμ•„λ΄„μœΌλ‘œμ¨ $\\beta$-λ™μΉ˜ 관계인지 검사가 κ°€λŠ₯ν•˜λ‹€." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Haskell", "language": "haskell", "name": "haskell" }, "language_info": { "codemirror_mode": "ihaskell", "file_extension": ".hs", "name": "haskell", "pygments_lexer": "Haskell", "version": "8.6.5" } }, "nbformat": 4, "nbformat_minor": 4 }