F#: 프로그래밍의 즐거움
닷넷계의 함수형 프로그래밍 언어라는 호기심에 처음 시작했던 F#, 하스켈이나 스칼라같은 다른 함수형 언어에 비하면 그 개념이 직관적이어서, 나름의 불편함이 있음에도 요즘 개인 프로젝트를 즐겁게 작업하고 있습니다.
좋아하는 점 중 하나는 타입 선언이 거의 필요 없다는 점인데요, 비슷한 포지션의 스칼라(F#: 닷넷 위의 함수형 언어, 스칼라: JVM 위의 함수형 언어)와 비교해보면 차이가 극명합니다. 어떻게 보면 거의 간결함으로 유명한 파이썬에 비교해볼만 합니다. 가끔 타입 추론에 실패해서 타입을 넣어야하는 경우가 있기는 한데, 매번 입력해야 하는 수고에 비하면 확실히 편합니다.
// F#
let intList = [1; 2; 3]
let charArray = [|'a'; 'b'|]
let two = 2
let add sequence intValue =
let length = Seq.length sequence // F#의 Seq는 IEnumerable
length + intValue
let answer = add intList two // 5
let answer2 = add charArray two // 4// Dotty(Scala 3)
val intList = List(1, 2, 3)
val charArray = Array('a', 'b')
val two = 2
def add[A](sequence: Seq[A], intValue: Int) = // Scala의 Seq는 모든 Collection의 인터페이스
val length = sequence.length
length + intValue
val answer = add(intList, two) // 5
val answer2 = add(charArray, two) // 4문법이 조금 이상하게 보이기는 해도 OOP를 (함수형 언어 중에서도) 잘 지원하는 편이고 닷넷 플랫폼 위에서 도는 것도 나름 강점이라고 생각합니다. Don Syme의 The F# Path To Relaxation를 보면 산업계에 함수형 패러다임을 조금 더 쉽게 보급하기 위해 기존에 널리 쓰이는 플랫폼에 호환되게 만들었다...라는 뉘앙스의 설명이 나오는데, F# 그 자체로는 산업계 전반에 큰 영향을 주지 못했지만 방향성은 옳다고 생각합니다.
이 언어로 프로그래밍을 하는 것을 더 재미있게 만들어주는 것은 바로 UI 포함한 프로그램을 만드는 게 매우 쉽다는 점인데요, 이는 닷넷 플랫폼의 특성과 Elmish라는 라이브러리에서 기인합니다.
대부분의 경우 닷넷 = C#이라는 공식이 있어서 닷넷을 이용한 웹 개발, 혹은 모바일 개발은 C#으로만 가능하다고 생각하기 마련입니다. 하지만 닷넷(코어) 플랫폼에서 돌아가는 언어라면 이론적으로 마이크로소프트에서 개발한 대부분의 기능을 사용할 수 있죠. F#도 닷넷에서 정식으로 지원되는 언어인 만큼, Xamarin Forms나 Blazor 등을 이용한 개발이 가능합니다.
여기에 화룡점정은 바로 Elmish인데요, Elm의 아키텍쳐, 즉 MVU(Model-View-Update)를 F#으로 이식한 라이브러리입니다. 자바스크립트로 빗대어 이야기하면 리액트와 리덕스가 합쳐진 느낌이라고 보시면 되겠습니다. 개인적으로 F#은 기본이 함수형 언어인 만큼 패턴 매칭이 기본 지원이므로 자바스크립트(혹은 타입스크립트)의 조합보다 좀 더 편하게 느끼고 있습니다.
// F#, 카운터 예제
// https://github.com/fable-compiler/fable2-samples/blob/master/minimal/src/App.fs
module App
(**
The famous Increment/Decrement ported from Elm.
You can find more info about Elmish architecture and samples at https://elmish.github.io/
*)
open Elmish
open Elmish.React
open Fable.React
open Fable.React.Props
// MODEL
type Model = int
type Msg =
| Increment
| Decrement
let init() : Model = 0
// UPDATE
let update (msg:Msg) (model:Model) =
match msg with
| Increment -> model + 1
| Decrement -> model - 1
// VIEW (rendered with React)
let view (model:Model) dispatch =
div []
[ button [ OnClick (fun _ -> dispatch Increment) ] [ str "+" ]
div [] [ str (string model) ]
button [ OnClick (fun _ -> dispatch Decrement) ] [ str "-" ] ]
// App
Program.mkSimple init update view
|> Program.withReactSynchronous "elmish-app"
|> Program.withConsoleTrace
|> Program.run닷넷의 멀티플랫폼 개발(Xamarin Forms를 이용한 모바일, GTK, WPF 개발 + Blazor를 이용한 WASM개발)과 Elmish를 합치면 리액트와 리액트 네이티브를 이용해 공용 라이브러리 + 플랫폼 전용 코드 개발이 가능하게 됩니다.
물론 꿈은 높지만 현실은 그에 미치지 못하는데, 이는 Blazor WASM이 아직 프리뷰 수준이고, 이를 이용한 F#의 프로젝트인 Bolero는 아예 0.12버전이며, Xamarin Forms를 Elm처럼 사용 가능하게 해주는 Fabulous도 아직 정식버전이 나오지 않았습니다. 거기다 F#의 인지도까지 고려하면...
이런 UI개발 말고도 좋아하는 점은 많아서, 언어적으로 암시적 파라미터가 없다던가(Computational Expression), 별도의 라이브러리를 쓰지 않고 메시지 기반 비동기 처리가 가능한 Mailbox 프로세서가 있다던가, ML(Meta Language) 방언이라던가(취향)... 등등이 있습니다.
이제 OCaml의 Functor만 들어오면 소원이 없겠지만, C#과의 호환성을 위해 그럴 일이 일어날 가능성이 0에 수렴하므로 눈물을 삼킵니다...