{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Currying, curry, uncurry\n", "\n", "하스켈의 모든 함수는 인자를 1개씩만 받는다. (우리가 05번 노트에서 배울 람다계산법도 그러하다)\n", "\n", "그러면 인자를 두개 받는 함수는 그럼 어떻게? 예를 들면 수학에서 $f(x,y)$ 이런 건 어떻게 표현? \n", "\n", "나는 저것도 인자를 1개 받는다고 취급하겠다. 무슨 이야기냐 하면 ...\n", "\n", "$(x,y)$라는 순서쌍을 하나 만들어서 한개의 순서쌍을 괄호 없이 $f$로 호출" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "p :: (Int,Int) -- 수학에서는 Int x Int \n", "p = (2,3)\n", "\n", "-- add도 인자를 1개 받는데 그 받는 인자의 타입이 마침 순서쌍일 뿐 ...\n", "addU :: (Int,Int) -> Int\n", "addU (x,y) = x + y\n", "-- addU p = case p of (x,y) -> x + y\n", "\n", "addU p" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "그럼 이건 뭔데??? 아 그거는 ...\n", "\n", "`addC`는 `Int`값을 하나만 받는 함수야. 그리고 `Int -> Int` 함수값을 돌려줘!\n", "\n", "(뭐 필요하면 그 리턴값에 또 `Int`값 하나를 더 줘서 한번 더 호출해 보던가 말던가 그건 니가 알아서 하고)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "addC :: Int -> Int -> Int\n", "addC x y = x + y\n", "-- addC x = f where f y = x + y\n", "\n", "addC 2 3" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/html": [ "a2 :: Int -> Int" ], "text/plain": [ "a2 :: Int -> Int" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "5" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "102" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "a2 = addC 2\n", "\n", ":type a2\n", "\n", "a2 3\n", "a2 100" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "이런 사실상 같은 일을 하는데 타입이 조금씩 다른 이런 함수들을 생각해 볼 수 있다.\n", "```haskell\n", "addU :: (Int,Int) -> Int\n", "addU (x,y) = x + y\n", "\n", "addC :: Int -> Int -> Int\n", "addC x y = x + y\n", "```\n", "\n", "addU가 굉장히 복잡한 기능이고 외부라이브러리는 addU 스타일로 되어 있는데,\n", "우리 프로젝트는 addC같은 스타일로 작업하고 있는 경우에 ...\n", "\n", "addC를 새로 정의하지 않고 addU를 addC의 타입으로 변환해주는 고차함수를 `curry`라고 합니다.\n", "\n", "반대 상황의 경우에 addC를 addU의 타입으로 변환해주는 고차함수를 `uncurry`라고 합니다." ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/html": [ "addU :: (Int, Int) -> Int" ], "text/plain": [ "addU :: (Int, Int) -> Int" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "8" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "addC' :: Int -> Int -> Int" ], "text/plain": [ "addC' :: Int -> Int -> Int" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "8" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ ":type addU\n", "addU (3,5)\n", "\n", "addC' = curry addU\n", ":type addC'\n", "addC' 3 5" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/html": [ "addC :: Int -> Int -> Int" ], "text/plain": [ "addC :: Int -> Int -> Int" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "8" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "addU' :: (Int, Int) -> Int" ], "text/plain": [ "addU' :: (Int, Int) -> Int" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "8" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ ":type addC\n", "addC 3 5\n", "\n", "addU' = uncurry addC\n", ":type addU'\n", "addU' (3,5)" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/html": [ "curry :: forall a b c. ((a, b) -> c) -> a -> b -> c" ], "text/plain": [ "curry :: forall a b c. ((a, b) -> c) -> a -> b -> c" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "uncurry :: forall a b c. (a -> b -> c) -> (a, b) -> c" ], "text/plain": [ "uncurry :: forall a b c. (a -> b -> c) -> (a, b) -> c" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ ":type curry\n", ":type uncurry" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [], "source": [ "curry :: ((a, b) -> c) -> (a -> b -> c)\n", "curry fu = fc\n", " where fc x y = fu (x,y) f" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Redundant bracket
Found:
(curry addU) 5
Why Not:
curry addU 5
" ], "text/plain": [ "Line 2: Redundant bracket\n", "Found:\n", "(curry addU) 5\n", "Why not:\n", "curry addU 5" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "8" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "8" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "addU (5,3)\n", "(curry addU) 5 3" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [], "source": [ "uncurry :: (a -> b -> c) -> ((a, b) -> c)\n", "uncurry fc = fu\n", " where fu (x,y) = fc x y -- fc를 이용해서 작성" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Redundant bracket
Found:
(uncurry addC) (5, 3)
Why Not:
uncurry addC (5, 3)
" ], "text/plain": [ "Line 2: Redundant bracket\n", "Found:\n", "(uncurry addC) (5, 3)\n", "Why not:\n", "uncurry addC (5, 3)" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "8" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "8" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "addC 5 3\n", "(uncurry addC) (5,3)" ] }, { "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 }