Welcome to F#(11) - 차별을 권장하는 언어인거임?!?!

F# 2009. 7. 8. 22:51 Posted by 알 수 없는 사용자

- 이말이 사실인게냐

discriminate는 (1)여러가지가 있을때 그것들이 서로 다르다는 걸 인식할 수 있다는 의미 (2) 특정한 단체의 사람들에게 against해서 쓰일때는 그 사람들에게 뭔가 부당하게 불이익이나 이익을 주는 의미를 가지고 있습니다.

즉, 둘다 차이에 근거한 의미인데요 첫째는 구별정도가 되겠고 둘째는 차별정도가 되겠네요. F#은 Discriminated Union(이하 union)이라는 아주 쓸모있는 기능을 가지고 있습니다. 그렇다면 F#은 차별을 권장하는 언어로서 인류발전에 그닥 긍정적이지 못한 언어일까요? 다행히 F#에서의 Discriminated는 첫번째인 구별의 의미로 쓰입니다.(뭐가 다행이지?-_-)


- 영단어엔 관심없는거임. 소스내놓으라해.

union의 형태는 아래와 같습니다. 


  type type-name =
   | case-identifier1 [of type1 [ * type2 ...]
   | case-identifier2 [of type3 [ * type4 ...] 


type키워드에 타입이름이 따라오고요 그리고 등호기호, 그리고 수직파이프(|) 문자로 나눠지는 식별자와 식별자의 타입리스트가 이어집니다. 저기서 각각의 식별자(case-identifier)를 discriminator(이하 구분자)라고 하는군요. 바로 차별구분자인거죠. 사칙연산 계산기를 구현하는 짧막한 코드를 완성해가면서 알아볼까요?


 type Expr =
    | Num of float
    | Add of Expr * Expr
    | Sub of Expr * Expr
    | Mul of Expr * Expr
    | Div of Expr * Expr


위 코드는 간단한 사칙연산에 필요한 구분자를 union을 이용해서 선언한 코드입니다. 다섯개의 구분자를 정의하고 있는데요. Num은 그냥 float타입이고, 나머지는 float * float인 tuple타입입니다. 나머지코드를 보시기전에 이 union만 가지고 이야기 해보도록 하죠. 이걸 어케 쓸까요? 


 

위의 그림을 보시면, 저렇게 쓰는거구나~ 하고 아실 수 있습니다. 구분자의 이름을 주고 괄호안에 구분자의 타입에 해당하는 값을 넣어주면 되는거죠. 그러면 Expr타입의 Num이라는 구분자이고 값은 float타입인 5.0을 가지고 있구나~ 하고 알마먹는 것이죠. Add도 마찬가지로 이해할 수 있습니다. 그리고 위의 union의 정의에 이어서 계산에 쓸 수식을 하나 정의해보죠. 

 let expr = Mul(Add(Num(5.0), Num(6.0)), Div(Num(5.0), Num(2.0))) // (5+6) * (5 /2)


주석에 나와있듯이 (5+6) * (5/2)를 위의 구분자로 표현한 수식입니다. 그러면, union을 이렇게 선언해서 구분자를 저렇에 선언한다는건 알겠는데, 저걸 어따써먹는건지 하는 궁금증이 생깁니다. union과 찰떡궁합인게 바로 pattern matching입니다. 아래의 코드를 보시죠

 let rec Calc expr =
    match expr with
    | Num num -> num
    | Add (e1, e2) -> (Calc e1) + (Calc e2)
    | Sub (e1, e2) -> (Calc e1) - (Calc e2)
    | Mul (e1, e2) -> (Calc e1) * (Calc e2)
    | Div (e1, e2) -> (Calc e1) / (Calc e2)

 
위의 코드는 제귀호출이 가능한 Calc라는 메서드인데요 expr이라는 인자를 하나 받습니다. 그리고 그 expr을 가지고 일치하는 패턴을 찾습니다. 말로 하지 말고 그림으로 하겠습니다! 아래의 그림을 보시져.(잘 안보이심 클릭해서 크게보시길...-_-)
 

 

왼쪽 상단은 F# Interactive에서 입력한 부분이고, 오른쪽 하단은 패턴매칭하는 코드 부분이죠. Num(5.0)의 실제 타입은 "Num 5.0"이고 그게 그대로 "Num num"부분에 매칭이 되면서, num의 값은 5.0이 되는거죠. 패턴매칭의 결과로 (Num 5.0) 은 그냥 5.0을 리턴합니다. 그리고 Add(Num 4.0,Num 9.0)도 각각의 Num이 e1, e2에 매칭이 돼서 Calc를 다시 호출하는 모습입니다. 물론 결과적으로 (Num 4.0) -> 4.0, (Num 9.0) -> 9.0이 리턴되면서 두수의 합이 리턴되겠죠. 그러면 마지막으로 결과를 출력합니다.
 

 Calc expr |> printfn "%f"


위의 코드를 실행한 결과는 아래와 같습니다.
 


제대로 결과가 출력된 게 보이시죠? ㅋㅋㅋ. 그럼 오늘도 지난번 처럼 ildasm을 통해서 IL코드를 둘러볼까 합니다.

 
위 사진을 보시면 지난 포스트의 curry처럼 Expr도 클래스로 선언된걸 확인하실 수 있고, union의 구분자중의 하나인 Num도 Expr내부에 중첩된 클래스로 선언되어 있는걸 보실 수 있습니다. 그리고 Num이 float을 하나 가지는데 그게 num1이라는 이름으로 선언되어있는 걸 IL코드를 통해서도 확인해보실 수 있습니다. 즉, 내부적으로는 구분자별로 클래스를 선언해서 타입으로 검사를 하는걸로 생각할 수 있겠네요. 아래에 보시면 그 타입검사를 위한 메서드들이 선언되어있는걸 확인하실 수 있습니다.
 

 

그리고 마지막으로 MSDN에 나와있는 예제를 하나 보도록 하겠습니다. 

type MilkOption =
   | Nonfat
   | TwoPercent
   | Whole
   | Soy
   | Rice
  
type FlavorOption = string
  
type Brand = string

type Size =
   | Short
   | Tall
  
type TeaFlavor = string
type Shots = int

type CoffeeType =
   | Drip
   | EspressoShot
   | Cappuccino
   | Latte of Size * MilkOption * Shots
   | FlavoredLatte of Size * MilkOption * FlavorOption * Shots

type Drink =
   | Can of Brand
   | Coffee of CoffeeType
   | Tea of TeaFlavor

let drink1 = Can("Coke")
let drink2 = Coffee(Drip)
let drink3 = Coffee(Latte(Tall, Nonfat, 2))
// A single short soy latte with hazelnut
let drink4 = Coffee(FlavoredLatte(Short, Soy, "Hazelnut", 1))

union을 통해서 커피가 캔인지 뽑은 커피인지, 커피이외의 차종류인지부터 시작해서 커피의 종류에서, 사이즈, 샷의횟수등 까지 절묘하게 조합하는 모습을 보실 수 있습니다.

 

- 정리하며

F#은 이렇게 union을 쉽게쓸 수 있는 언어적 특성덕분에 DSL(Domain Specific Language, 다른말로 Language Oriented Progamming이라고도 함)을 잘 지원할 수 있는 능력이 있습니다. 물론 DSL은 그리 쉬운 주제는 아니지만, F#과 함께 천천히 시작해보는 것도 나쁘진 않을 거 같습니다. DSL이나 LOP에 대해서 더 설명을 드릴 수 있으면 좋겠지만, 내공이 허락치 않는군요-_-;;;;;;;;;;


- 참고자료

1.  http://msdn.microsoft.com/en-us/library/dd233226(VS.100).aspx
2.  http://sdasrath.blogspot.com/2009/02/20090220-f-types-discriminated-unions.html
3. Expert F#,  Don Syme, Adam Granicz, Antonio Cisternino, Apress

[ASP.NET 4.0] 2. AJAX - Declarative Client Template Rendering

ASP.NET 4.0 2009. 7. 8. 17:43 Posted by 알 수 없는 사용자
New Feature of Ajax

ATLAS라는 코드명으로 2006년 ASP.NET에 추가된 Ajax가 점점 견고해 지고 있습니다. 2006년 CTP버전 이었던 ATLAS를 겁없이(?) 프로젝트에 적용했었던 기억이 떠오르는 군요. 2006년을 기억하면, 참 MS에서 새로운 기술이 쏟아져 나오던 한해 였습니다. Vista가 공개 되고 WinFX와 WPF, WF(그때는 WWF 로 소개 되었었죠), WCF, ASP.NET에 Ajax 등등 많은 기술이 소개되어 .NET 개발자들의 정신 건강을 악화시켰던 때였습니다.
Ajax는 Google을 선두로 하여 Web 2.0에 적절한 패러다임을 제공하였으며, 국내에서도 많은 파장을 일으켰습니다. 특히, MS에서 나온 Ajax는 개발자의 개발 편의성을 확장시켜 Ajax 대중화에 큰 역활을 하였습니다.

이번 ASP.NET 4.0에 Ajax는 Data Provider의 접근 용이성에 중점을 둔듯 합니다. WCF와 ADO.NET을 이용하여 Client Based Development를 확장시켰으며, DataView는 Client Side에서 개발자가 편하게 화면을 개발 할 수 있도록 리스트 컨트롤을 제공하고 있습니다.

Client Template Rendering - DataView

DataView는 이번에 추가된 기능으로 이전까지는 Server Control을 이용한 리스트를 제공한 반면, Client Side Control을 사용함으로써, Server의 부하를 줄일 수 있도록하는 기능입니다. 예전에는 반복문을 통해 DOM을 생성한다든지, 아니면 개발자 자신의 라이브러리를 활용하거나, Third party 솔루션을 이용하는 방법이 있었습니다만, System.Web.Extention 4.0버전 부터는 기본적으로 DataView라는 컨트롤을 제공해 주고 있습니다. 그리고, 굳이 ASP.NET 언어가 아닌 다른 Framework에서도 사용가능한 독립형 스크립트로 제공하여 주고 있어 플랫폼 대한 제약을 많이 완화 시켰습니다.


간략하게 기능을 알아보도록 하겠습니다.

선언적 구문으로 생성하는 DataView

WebSite 프로젝트를 생성하고 간단한 html문서 또는 aspx 문서를 생성해 보겠습니다. <head>섹션에
<script type="text/javascript" src="../MicrosoftAjax/MicrosoftAjax.debug.js"></script><script type="text/javascript" src="../MicrosoftAjax/MicrosoftAjaxTemplates.debug.js"></script>

AJAX Template을 사용하려면 이 스크립트 참조를 꼭 기입하여야 정상적으로 Template이 생성되는 보실 수 있습니다. 그리고 Body 부분에 해당 Namespace와 Command를 추가해 줍니다.
<body xmlns:sys="javascript:Sys" xmlns:dataview="javascript:Sys.UI.DataView" sys:activate="*">
xmlns:sys="javascript:Sys"는 Sys라는 Namespace를 등록 시켜 줌으로써 선언적(Declarative) 또는 명령적(Imperative)인 모든 Template을 활성화 하는데 필요합니다. 아마도 Ajax를 프로그래밍적으로 접근 하셨던 분들은 Microsoft Ajax Library의 Namespace가 Sys. 이렇게 접두어를 붙여 사용되는 것을 보셨겁니다. 그리고 나머지 두 Attribute는 선언적(Declarative)으로 활성화하거나 바인딩 하는데 필요한 Attribute입니다. dataview또한 네임스페이스로써 Sys.UI.DataView의 AJAX 컨트롤을 의미합니다. 그리고 sys:activate="*"라는 Attribute는 페이지 로드시에 Template을 바인딩하는 특정 개체를 의미하는데 '*'(Asterisk)를 편의상 어떤것이든 활성화 하겠다는 뜻이고 만약 pane1, panel2에 Template을 바인딩 하려면 sys:activate="panel1, panel2"라고 명시적으로 코딩하시면 됩니다.
그리고 실제 Template이 들어갈 개체의 코드를 구현하여 보겠습니다.

<ul id="testDataView" class="sys-template" sys:attach="dataview" dataview:data="{{ testData }}">        <li>            <span class="name">{{ Name }}</span>            <span class="value">{{ Value }}</span>        </li></ul>
ul안에 id와 class 그리고 sys:attach, dataview:data와 같은 예전에 보던 Attribute와 생전 처음 쌩뚱 맞은 Attribute가 ul 태그 안에 들어와 있는 것을 보실 수 있습니다. 일단 "sys-template"이 거슬리는 군요.
sys-template은 일종에 예약된 스타일이라고 이해하시면 됩니다. 만약 Template을 구현 하고 class에 sys-template을 명시적으로 넣어 주시지 않으시면, 효과가 즉빵 나타납니다. 어떤 효과일까요? 리스트가 아예 안나옵니다. 헐~ 필자도 처음에는 내 나름대로의 스타일을 줬다가 몇분 삽질하고, 이런 교훈을 얻었습니다. 아무튼  testStyleSheet.css스타일 시트를 만드셨다면 그 시트 안에는 .sys-template { display:none; } 이라는 스타일이 있어야 합니다. 다시 정리 하자면 sys-template 은 Template에 바인딩이 일어나기 전까지 Template을 숨기는 예약된 스타일이라고 정의하겠습니다. 

그리고, sys:attatch는 또 뭐하는 아이이길래 우리를 헷깔리게 하는 것일까요? 음, 예전에 Microsoft AJAX Library를 프로그래밍적으로 다루어 보셨던 분들이라면 생소 하지 않는 $Create라는 메서드를 기억하실 겁니다. 이놈은 개체를 생성하는 아이인데 Sys.으로 파생되는 개체들을 생성하는 메서드라고 할 수 있습니다. 즉 Microsoft AJAX Library에서만 파생된 개체들을 쉽게 생성하고자 만들어진 메서드입니다. 그럼 sys:attatch와 $Create와는 무슨 관계일까요? 답은 같은 놈입니다. 다만 선언적으로 태그의 Attribute에 위치하느냐, 프로그래밍적으로 접근하느냐하는 방법의 차이일 뿐이지 같은 의미를 지녔습니다. 마지막으로 dataview:data는 body태그에서 Namespace를 정의해 주었던거 생각 나시죠? 그 접두어에 data는~~~~~~~ 네 맞습니다. Data Source입니다. 우리가 리스트를 주욱 바인딩 할 데이터 소스 개체를 정의해 주는 Attribute입니다.
그럼, 이제 어느정도 Attribute에 대한 이해가 되었으리라 생각하고 다음 코딩으로 넘어 가겠습니다.

Add array DataSource

다음과 같이 Array로 DataSource를 생성합니다. 다음에는 ADO.NET과 WCF로 바인딩하는 포스팅을 하도록 하겠습니다.
<script type="text/javascript">        
var testData = [
            { Name: "홍길동", Value: "의적" },
            { Name: "김혜자", Value: "영화배우" },
            { Name: "원빈", Value: "영화배우" },
            { Name: "김태희", Value: "이쁜이" },
            { Name: "전지현", Value: "절세미인" },
            { Name: "2PM", Value: "가수" },
            { Name: "장동건", Value: "영화배우." },
            { Name: "카라", Value: "귀염둥이들" },
            { Name: "이수근", Value: "코메디언" },
            { Name: "강호동", Value: "돼랑이" },
            { Name: "유재석", Value: "메뚜기" },
            { Name: "이효리", Value: "횰" },
            { Name: "정형돈", Value: "정체불명" },
            { Name: "길", Value: "가수" }        ];
</script>

다들 아시겠지만 굳이 부연 설명 드리도록 하겠습니다. javascript는 함수형 언어로써 강력한 기능을 제공합니다. 보시는 바와 같이 단순히 Array 이지만 testData라는 개체에 Name과 Value라는 Attribute가 있는 개체들의 집합이 들어 가게 되는 것입니다. 우리가 생각 하는 new의 연산자와 javascript의 new 연산자는 다른 의미라는 것을 알고 계실 듯 합니다. 여기에서도 유추를 하실 수 있습니다. 혹, testData[0].Name일 경우 홍길동이 나타나는 결과를 얻으실 수 있습니다.
이제 실제 결과 페이지를 보고 이번 포스팅을 마무리 하겠습니다.

지난 6월 10일 VSTS 2010 팀에서 세미나를 진행하였습니다. 세미나 프레젠테이션은 MEF 세미나 자료 에서 볼 수 있습니다.

그리고 얼마 전에 촬영한 동영상도 공개가 되었습니다. VSTS 2010 은 굉장히 큰 규모의 개발 도구, 개발 플랫폼 등의 버전 업으로 아직도 많은 부분을 알려드리지 못했고, 미처 저희들도 모두 알지 못하는 부분도 많습니다.

하지만 남들보다 먼저 접해본 분야이고 이것을 알려드리기 위해 진행한 세미나입니다. 아래의 동영상을 시청하시고 VSTS 2010 에 많은 관심을 가져주세요. ^^

   

강보람 - C# 연대기 - C# 의 Before/After

   

공성의 - VSTS 2010 의 소프트웨어 품질 관리

   

김병진님의 - VSTS 2010 Architecture & UML

   

   

엄준일 ASP.NET MVP - Managed Extensibility Framework

   

최흥배 C++ MVP - Visual C++ 10, C++0x 그리고 Concurrency Runtime