函數兄 프로그래밍

위키百科, 우리 모두의 百科事典.

函數兄 프로그래밍 (函數型 프로그래밍, 英語 : functional programming )銀 資料 處理를 數學的 函數 의 計算으로 取扱하고 狀態와 可變 데이터를 멀리하는 프로그래밍 패러다임 의 하나이다. 命令形 프로그래밍 에서는 狀態를 바꾸는 것을 强調하는 것과는 달리, 函數兄 프로그래밍은 函數의 應用을 强調한다. 프로그래밍이 이 아닌 式이나 宣言으로 遂行되는 宣言型 프로그래밍 패러다임을 따르고 있다. [1] 函數兄 프로그래밍은 1930年代에 計算可能性, 決定問題, 函數定義, 函數應用과 再귀를 硏究하기 위해 開發된 形式體系人 람다 臺數 에 根幹을 두고 있다. 多數의 函數兄 프로그래밍 言語 들은 람다 演算을 발전시킨 것으로 볼 수 있다.

數學的 函數 와 命令形 프로그래밍에서 使用되는 函數는 差異가 있는데, 命令形의 函數는 프로그램의 狀態의 값을 바꿀 수 있는 副作用이 생길 수 있다. 이 때문에 命令形 函數는 參照 透明性이 없고, 같은 코드라도 實行되는 프로그램의 狀態에 따라 다른 結果값을 낼 수 있다. 反對로 函數兄 코드에서는 函數의 出力값은 그 函數에 入力된 引受에만 依存하므로 引受 x에 같은 값을 넣고 函數 f를 呼出하면 恒常 f(x)라는 結果가 나온다. 副作用을 除去하면 프로그램의 動作을 理解하고 豫測하기가 훨씬 쉽게 된다. 이것이 函數兄 프로그래밍으로 開發하려는 核心 同期中 하나이다.

Hope같은 最初의 純粹 函數兄 言語는 商業的 소프트웨어 開發보다는 學界에서 많은 關心을 받았다. 하지만 커먼 리스프 , 스킴 , ISLISP, 클로져 , Racket, 얼랭 , OCaml , 하스켈 , 스칼라 , F# 같은 主要 函數兄 言語들은 廣範圍한 機關에서 産業的이고 商業的인 應用 프로그램 開發에 使用되고 있다. 函數兄 言語는 R (統計), 매스매티카 (記號와 數論 數學), J, K 와 Kx 시스템 基盤 (財政 시스템)에서 나온 Q, XQuery/ XSLT ( XML ), Opal 같은 特定 分野 프로그래밍 言語(Domain Specific Language)에서도 使用되고 있다. 많이 쓰이는 特定 分野 宣言 言語인 SQL lex / Yacc 는 特히 可變값을 回避하는데 있어 函數兄 言語의 要素들을 使用한다.

函數兄 스타일의 프로그래밍은 函數兄 言語로 別途로 設計되지 않은 言語에서도 可能하다. 例를 들어, 命令形人 프로그래밍 言語는 函數兄 프로그래밍 槪念을 適用하는 法을 說明하는 冊에서 主題로 다루기도 했다. C# 3.0은 函數兄 스타일의 쓸 수 있는 構文을 追加했다.

歷史 [ 編輯 ]

알론組 處置 가 1930年代에 開發한 람다 臺數 는 函數에 對한 理論的 基盤을 세웠다. 이것은 프로그래밍 言語가 아니라 數學的 抽象化였지만, 이것은 函數兄 프로그래밍의 根幹을 이루었다.

처음으로 만들어진 函數兄 프로그래밍 言語는 IPL 이었다. 존 매카시 가 만든 리스프 는 훨씬 向上된 函數兄 프로그래밍 言語였고, 이것은 現代的 函數兄 프로그래밍의 여러 特徵을 가지고 있었다. 리스프를 發展시키고 簡單하게 만든 言語로 스킴 도 있다.

1970年代에 로빈 밀너 ML 을 開發하였고, 데이비드 터너 미란다 를 開發하였다. ML의 여러 "方言"李 開發되었고, 現在 가장 많이 쓰이는 方言은 OCaml 이다.

1980年代에는 그동안의 函數兄 프로그래밍에 對한 硏究를 바탕으로 純粹 函數兄 言語인 하스켈 이 만들어졌다.

純粹한 函數 [ 編輯 ]

純粹한 函數(pure function) 란, 副作用(side-effect) 이 없는 函數, 卽, 函數의 實行이 外部에 影響을 끼치지 않는 函數를 뜻한다. 따라서 純粹한 函數는 스레드 安全 하고, 竝列的인 計算이 可能하다.

다음과 같은 코드에서 f는 純粹한 函數라고 하자.

y = f(x) * f(x);

이 때, f가 두 番 重複되는 것을 다음과 같이 最適化할 수 있다.

z = f(x);
y = z * z;

이렇게 하면, f(x)를 計算하는 過程이 두 番에서 한 番으로 줄어들지만 두 코드의 結果는 恒常 같게 된다.

하지만, f가 純粹하지 않은 函數인 境遇에는 이러한 方式을 使用할 수 없다. 다음의 코드에서 random이 任意의 값을 주는 函數라고 하자.

y = random() * random();

函數 random은 呼出할 때마다 結果가 달라질 수 있는, 卽 副作用을 發生시키는 函數다. 따라서, 이 코드는

z = random();
y = z * z;

와는 다른 結果를 갖게 된다. 마찬가지로

 y
 =
 printf
(
"x"
)
 *
 printf
(
"x"
);

에서 printf가 畵面에 글字를 出力하는 函數라면, 이 函數는 副作用을 發生시키며 따라서 純粹한 函數라고 볼 수 없다. C의 printf 函數는 "x"가 正常的으로 출력되었느냐 與否에 따라 0이나 1 값을 返還한다. 따라서 正常的인 境遇 y는 1이 되겠지만, printf 函數가 제대로 出力하지 못하는 境遇 0이 될 수도 있으므로 純粹한 函數라고 볼 수 없다.

匿名 函數 [ 編輯 ]

匿名 函數(anonymous function) 란, 이름이 없는 函數를 뜻한다. 傳統的인 命令形 言語에서는 모든 函數에 이름이 附與되어야만 한다. 예컨대 引受를 제곱하는 函數를 C 言語 로 作成한다면 다음과 같이 作成할 수 있을 것이다.

 int
 square
(
int
 x
)
 {
 return
 x
 *
 x
;
 }

그러나 函數兄 言語에서는 이 函數를 匿名函數로 作成할 수 있다.

다음은 하스켈 로 作成한 제곱 函數이다.

 \
x
 ->
 x
 *
 x

여기서 \x 의 逆빗금 \ 은 람다 計算法의 람다를 意味한다. 位 函數를 람다 表現으로 나타내면 가 된다.

C++11 에서는 다음과 같이 作成한다.

 [](
int
 x
)
 ->
 int
 {
 return
 x
 *
 x
;
 }

高階 函數 [ 編輯 ]

高階 函數(higher-order function) 란, 函數를 다루는 函數를 뜻한다. 事實 函數兄 言語에서는 含水度 '값(value)'으로 取扱한다. 그러므로 精髓 1이나 引受를 제곱하는 函數나 同等한 立場에서 다룰 수 있다. 精髓를 函數의 引受로 傳達할 수 있듯이 어떤 含水度 다른 函數의 引受로 傳達할 수 있다. 마찬가지로 函數의 結果 값으로 精髓를 返還할 수 있듯이 函數를 返還할 수도 있다.

例를 들어서 1에서 10까지 數字로 이루어진 리스트의 各 元素를 제곱하고 싶다고 하자. 命令形 言語에서는 反復門을 利用하여 리스트를 훑어 가며 各 元素를 제곱하겠지만, 函數兄 言語에서는 리스트를 다루는 高階 函數로 이를 處理할 수 있다. 다음은 하스켈 을 利用하여 이를 遂行한 例를 보여준다.

 map
 (
\
x
 ->
 x
 *
 x
)
 [
1
..
10
]

여기서 [1..10] 은 1에서 10까지 數字로 이루어진 리스트 다. 高階 函數 map 은 첫 番째 引受로 주어진 函數(여기서는 제곱을 遂行하는 匿名函數)를 두 番째 引受로 주어진 리스트 의 各 元素에 適用한 結果 리스트를 返還한다. 位 코드를 遂行하면 다음과 같은 結果를 얻을 수 있다.

[1,4,9,16,25,36,49,64,81,100]

各州 [ 編輯 ]

外部 링크 [ 編輯 ]