F# 배우기 - slog

우였였 λ©‹μ§‘λ‹ˆλ‹€! C#이 사싀 많이 ν˜„λŒ€ν™” λ˜μ—ˆμ§€μš”.

1 Like

κ·Έλ ‡μŠ΅λ‹ˆλ‹€.

그런데, F# μ½”λ“œλ₯Ό λ³΄λ‹ˆ, μ•„λž˜ νŒ¨ν„΄ 맀칭에 λŒ€ν•œ 지원이 있으면, 쒋을 것 κ°™λ‹€λŠ” 생각을 ν•΄λ΄…λ‹ˆλ‹€.

// =>  source.Any() is false ? []
=>  source is [] ? []

사싀, Linq ν™•μž₯ λ©”μ„œλ“œμ— IsEmpty()κ°€ μ—†μ–΄μ„œ, 항상 λ³„λ„λ‘œ μ •μ˜ν•΄μ„œ μ“°κ³€ ν–ˆκ±°λ“ μš”.

public static bool IsEmpty(this IEnumerable<T> source) => !source.Any();

μ΄λ ‡κ²Œ μ •μ˜ν•˜λ©΄, μ½”λ“œ 가독성이 μ’‹μ•„μ§‘λ‹ˆλ‹€.

// =>  source.Any() is false ? []
=>  source.IsEmpty() ? []

μ΄κ²ƒλ³΄λ‹€λŠ” νŒ¨ν„΄ 맀칭이 더 쒋을 것 κ°™μŠ΅λ‹ˆλ‹€.

μΆ”κ°€

κ°‘μžκΈ°, F# 이 List λ₯Ό μ‚¬μš©ν–ˆλ‹€λŠ” 생각이 λ‚¬μŠ΅λ‹ˆλ‹€. C# 도 List λ₯Ό μ‚¬μš©ν•˜λ©΄,

    public static List<T> QuickSort<T>(this List<T> source)
        where T : IComparable<T> => source is [] ? []
    :[
        .. source[1..].FindAll(x => x.CompareTo(source[0]) < 0).QuickSort(),
        source[0],
        .. source[1..].FindAll(x => x.CompareTo(source[0]) >= 0).QuickSort(),
    ];
3 Likes

F#κ³Ό C# 비ꡐ : μ›Ή νŽ˜μ΄μ§€ λ‹€μš΄λ‘œλ“œ

사싀 λ³Έλ¬Έ λ‚΄μš©μ˜ 극적인 λΉ„κ΅λŠ” C#이 아직 using xxx; 문법을 μ§€μ›ν•˜μ§€ μ•Šμ•˜λ˜ 과거의 κΈ°μ€€μ΄κΈ°λŠ” ν•©λ‹ˆλ‹€.

F#μ—μ„œ νŠΉμ • μ›Ή νŽ˜μ΄μ§€λ₯Ό λ‹€μš΄λ‘œλ“œ ν•˜κ³  ν…μŠ€νŠΈ μŠ€νŠΈλ¦Όμ„ μ²˜λ¦¬ν•˜λŠ” 콜백으둜 이λ₯Ό μ²˜λ¦¬ν•˜λŠ” μ½”λ“œλ₯Ό μ‚΄νŽ΄λ΄…μ‹œλ‹€.

open System.Net
open System
open System.IO

let fetchUrl callback url =
    let req = WebRequest.Create(Uri(url))
    use resp = req.GetResponse()
    use stream = resp.GetResponseStream()
    use reader = new IO.StreamReader(stream)
    callback reader url

이에 ν•΄λ‹Ήν•˜λŠ” C# μ½”λ“œλŠ”,

class WebPageDownloader
{
    public TResult FetchUrl<TResult>(
        string url,
        Func<string, StreamReader, TResult> callback)
    {
        var req = WebRequest.Create(url);
        using (var resp = req.GetResponse())
        {
            using (var stream = resp.GetResponseStream())
            {
                using (var reader = new StreamReader(stream))
                {
                    return callback(url, reader);
                }
            }
        }
    }
}

으둜 가독성이 많이 λ–¨μ–΄μ§‘λ‹ˆλ‹€. λ¬Όλ‘ ,

using (var resp = req.GetResponse())
using (var stream = resp.GetResponseStream())
using (var reader = new StreamReader(stream))
{
}

으둜 μ€‘κ΄„ν˜Έλ₯Ό μ œκ±°ν•  수 μžˆμ§€λ§Œ 보닀 일반적인 κ²½μš°μ—λŠ” ν•„μš”ν•©λ‹ˆλ‹€.

C#의 졜근 λ¬Έλ²•μ—λŠ” λ‹€μŒκ³Ό 같이 μ“Έ 수 μžˆμŠ΅λ‹ˆλ‹€.

   using var resp = req.GetResponse();
   using var stream = resp.GetResponseStream();
   using var reader = new StreamReader(stream);

그런 λ‹€μŒ myCallback을 λ‹€μŒμ²˜λŸΌ μž‘μ„±ν•œ ν›„ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

let myCallback (reader:IO.StreamReader) url =
    let html = reader.ReadToEnd()
    let html1000 = html.Substring(0,1000)
    printfn "Downloaded %s. First 1000 is %s" url html1000
    html

let google = fetchUrl myCallback "http://google.com"

F#의 λ˜λ‹€λ₯Έ μœ μš©ν•œ κΈ°λŠ₯으둜 `베이크 인" ν•  수 μžˆλ„λ‘ λ§€κ°œλ³€μˆ˜λ₯Ό 맀번 μ „λ‹¬ν•˜μ§€ μ•Šμ•„λ„ λ©λ‹ˆλ‹€.

//베이크 인 ν•˜μ—¬ myCallbackλ₯Ό 기본으둜 μ‚¬μš©ν•˜λŠ” μƒˆλ‘œμš΄ ν•¨μˆ˜λ₯Ό λ§Œλ“¬
let fetchUrl2 = fetchUrl myCallback

/ test
let google = fetchUrl2 "http://www.google.com"
let bbc    = fetchUrl2 "http://news.bbc.co.uk"

let sites = ["http://www.bing.com";
             "http://www.google.com";
             "http://www.yahoo.com"]

sites |> List.map fetchUrl2

이에 λ™λ“±ν•œ C#μ½”λ“œλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

[Test]
public void TestFetchUrlWithCallback()
{
    Func<string, StreamReader, string> myCallback = (url, reader) =>
    {
        var html = reader.ReadToEnd();
        var html1000 = html.Substring(0, 1000);
        Console.WriteLine(
            "Downloaded {0}. First 1000 is {1}", url,
            html1000);
        return html;
    };

    var downloader = new WebPageDownloader();
    var google = downloader.FetchUrl("http://www.google.com",
                                      myCallback);

    // test with a list of sites
    var sites = new List<string> {
        "http://www.bing.com",
        "http://www.google.com",
        "http://www.yahoo.com"};

    // process each site in the list
    sites.ForEach(site => downloader.FetchUrl(site, myCallback));
}

ν˜„λŒ€ C#은 이제 F#κ³Ό 거의 λ™μΌν•œ μ½”λ“œλ₯Ό 생성할 수 μžˆμŠ΅λ‹ˆλ‹€.

var myCallback = (string url, StreamReader reader) =>
{
    var html = reader.ReadToEnd();
    var html100 = html[..100];
    Console.WriteLine($"Downloaded {url}. First 1000 is {html100}");
    return html;
};

var fetchUrl2 = (string url) => WebPageDownloader.FetchUrl(url, myCallback);

var google = fetchUrl2("http://www.google.com");
var bbc    = fetchUrl2("http://news.bbc.co.uk");

List<string> sites = [
    "http://www.bing.com",
    "http://www.google.com",
    "http://www.yahoo.com"];

sites.ForEach(i => fetchUrl2(i));

ν˜„λŒ€ C#에 이λ₯΄λŸ¬ κ·Έ 격차가 쀄긴 ν–ˆμ§€λ§Œ C#의 λ°œμ „ λ°©ν–₯이 F#의 μž₯점을 μ«“κ³  μžˆμ—ˆμŒμ„ μ•Œ 수 μžˆμ—ˆλ„€μš”.

4 Likes

F#의 4가지 핡심 κ°œλ…

λ‚΄μš©μ„ μ΄ν•΄ν•˜λŠ” 것과 μ΄ν•΄ν•œ κ²ƒμœΌλ‘œ ν•  수 μžˆλŠ” 것은 ν•˜λŠ˜κ³Ό λ•… μ°¨μ΄μž…λ‹ˆλ‹€. 슬슬 F#의 μž₯점과 νŠΉμ§•μ΄ νŒŒμ•…λ˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 벌써 며칠이 μ§€λ‚¬κ΅°μš”!

F#은 κ°•λ ₯ν•œ ν•¨μˆ˜ν˜• μ–Έμ–΄λ‘œ ꡬ사할 수 있기 λ•Œλ¬Έμ— λ‹€μŒμ˜ νŠΉμ§•μ„ μ‚΄νŽ΄λ΄μ•Ό ν•©λ‹ˆλ‹€.

C# 언어도 이제 ν•¨μˆ˜ν˜• μ–Έμ–΄μ˜ μ—¬λŸ¬ μž₯점을 μ·¨ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 그쀑 νŒ¨ν„΄ 맀칭도 μžˆμŠ΅λ‹ˆλ‹€.

객체 지ν–₯ λ³΄λ‹€λŠ” ν•¨μˆ˜ 지ν–₯

객체 지ν–₯ νŒ¨λŸ¬λ‹€μž„μ€ 역할을 κ°œμ²΄μ— λ‘μžλŠ” κ²ƒμž…λ‹ˆλ‹€. κ·Έλž˜μ„œ μƒνƒœμ™€ ν–‰μœ„κ°€ κ°œμ²΄λΌλŠ” 였브젝트둜 μ‘΄μž¬ν•˜κ²Œ λ©λ‹ˆλ‹€. 이에 λ°˜ν•΄ ν•¨μˆ˜ 지ν–₯은 데이터가 쀑심이 λ˜μ–΄μ„œ λ°μ΄ν„°μ˜ 흐름에 집쀑 ν•©λ‹ˆλ‹€. 그리고 λ‹€μŒμ˜ νŠΉμ§•μ„ 톡해 문제λ₯Ό ν’‰λ‹ˆλ‹€.

  • κ²°ν•©(Composition)
    ν•¨μˆ˜ 지ν–₯ ν”„λ‘œκ·Έλž˜λ°μ€ μž‘μ€ λ‹¨μœ„λ₯Ό κ²°ν•©ν•˜μ—¬ 큰 문제λ₯Ό ν‘ΈλŠ”λ° μ ν•©ν•©λ‹ˆλ‹€. μ΄λŠ” 객체 지ν–₯의 μΈν„°νŽ˜μ΄μŠ€λ₯Ό ν†΅ν•œ κ²°ν•©κ³Ό μœ μ‚¬ν•œ 점이 μžˆμŠ΅λ‹ˆλ‹€.
  • 뢄해와 λ¦¬νŒ©ν† λ§
    ν•¨μˆ˜ 지ν–₯은 객체 지ν–₯으둜 λ‚˜λˆŒ 수 μžˆλŠ” 것 μ΄μƒμœΌλ‘œ ν•¨μˆ˜ λ‹¨μœ„λ‘œ λ‚˜λˆŒ 수 μžˆμ–΄μ„œ 쀑볡 μ½”λ“œλ₯Ό μ’€ 더 μ–΅μ œν•˜κ³  μ½”λ“œ 읽기가 편리 ν•©λ‹ˆλ‹€.
  • 쒋은 λ””μžμΈ
    ν•¨μˆ˜ν˜• μ ‘κ·Ό 방식에 μ˜ν•΄μ„œ μžμ—°μŠ€λŸ½κ²Œ 관심사 뢄리, 단일 μ±…μž„ 원칙, κ΅¬ν˜„μ΄ μ•„λ‹Œ μΈν„°νŽ˜μ΄μŠ€ λ“± 쒋은 λ””μžμΈ 쀑 λ§Žμ€ 뢀뢄은 ν•¨μˆ˜ν˜• μ ‘κ·Ό λ°©μ‹μ˜ μžμ—°μŠ€λŸ¬μš΄ κ²°κ³Όμž…λ‹ˆλ‹€.

λ¬Έμž₯(Statement) λ³΄λ‹€λŠ” ν‘œν˜„μ‹(Expression)

F#은 ν•¨μˆ˜μ— μ˜ν•΄ λͺ¨λ“  μ½”λ“œ λΈ”λŸ­μ€ κ°’κ³Ό 깊게 μ—°κ΄€λ˜μ–΄ 있고 값은 λ°˜ν™˜ν•©λ‹ˆλ‹€. 더 큰 μ½”λ“œ λΈ”λŸ­μ€ 결합을 톡해 더 μž‘μ€ λΈ”λŸ­μ„ κ²°ν•©ν•˜μ—¬ λ§Œλ“€μ–΄μ§‘λ‹ˆλ‹€.

ν‘œν˜„μ‹ κΈ°λ°˜μ΄λž€ LINQ와 SQLκ³Ό 같은 ν˜•νƒœμž…λ‹ˆλ‹€.

λŒ€μˆ˜ μœ ν˜•

F#은 λ‹¨μˆœν•œ μœ ν˜•μ„ κ²°ν•©ν•˜μ—¬ μ’€ 더 λ³΅μž‘ν•œ μœ ν˜•μ„ λ§Œλ“€μ–΄ ν™œμš©ν•©λ‹ˆλ‹€. μ΄λŠ” 일반 μ–Έμ–΄μ˜ struct으둜 생각할 수 μžˆλŠ”λ° μœ λ‹ˆμ˜¨ μœ ν˜•μ˜ νŠΉμ§•μœΌλ‘œ 일반 볡합 μœ ν˜•κ³Ό κ΅¬λΆ„λ©λ‹ˆλ‹€.

type IntOrBool =
  | IntChoice of int
  | BoolChoice of bool

let y = IntChoice 42
let z = BoolChoice true

νŒ¨ν„΄ 맀칭

νŒ¨ν„΄ 맀칭은 λͺ¨λ“  쑰건에 ν•΄λ‹Ήν•˜λŠ” 값을 μ²˜λ¦¬ν•  수 μžˆλ„λ‘ ν•©λ‹ˆλ‹€.

match booleanExpression with
| true -> // true branch
| false -> // false branch
match aDigit with
| 1 -> // Case when digit=1
| 2 -> // Case when digit=2
| _ -> // Case otherwise
match aList with
| [] ->
     // Empty case
| first::rest ->

μ΄λŠ” κ°•λ ₯ν•΄μ„œ C#μ—μ„œλ„ 이제 μ‚¬μš© κ°€λŠ₯ ν•©λ‹ˆλ‹€.

μœ λ‹ˆμ˜¨ μœ ν˜•μ„ μ‚¬μš©ν•œ νŒ¨ν„΄ 맀칭

이 κΈ°λŠ₯은 맀우 κ°•λ ₯ν•΄μ„œ Rust λ“± μ΅œμ‹  ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄μ—μ„œ μ‚¬μš©λ˜κ³  있으며 λΉ λ₯΄κ³  μ •ν™•ν•˜λ©° 효율적인 μžλ£Œν˜•μ— λŒ€ν•œ 처리λ₯Ό κ°€λŠ₯ν•˜κ²Œ ν•©λ‹ˆλ‹€.

type Shape =        // define a "union" of alternative structures
    | Circle of radius:int
    | Rectangle of height:int * width:int
    | Point of x:int * y:int
    | Polygon of pointList:(int * int) list

let draw shape =    // define a function "draw" with a shape param
  match shape with
  | Circle radius ->
      printfn "The circle has a radius of %d" radius
  | Rectangle (height,width) ->
      printfn "The rectangle is %d high by %d wide" height width
  | Polygon points ->
      printfn "The polygon is made of these points %A" points
  | _ -> printfn "I don't recognize this shape"

let circle = Circle(10)
let rect = Rectangle(4,5)
let point = Point(2,3)
let polygon = Polygon( [(1,1); (2,2); (3,3)])

[circle; rect; polygon; point] |> List.iter draw

행동 지ν–₯ λŒ€ 데이터 지ν–₯ λ””μžμΈ

μ΄λŸ¬ν•œ νŒ¨ν„΄ 맀칭은 객체 지ν–₯의 κ΄€μ μ—μ„œλŠ” λͺ¨λ“  μœ ν˜•μ— λŒ€ν•œ λΆ„κΈ°κ°€ μΌμ–΄λ‚˜λ―€λ‘œ μ•ˆν‹°νŒ¨ν„΄ 처럼 λ³΄μž…λ‹ˆλ‹€. 객체 지ν–₯μ—μ„œλŠ” 좔상화λ₯Ό 톡해 μ–΄λ–€ μœ ν˜•μ΄λ“ μ§€ λ™μΌν•˜κ²Œ μ²˜λ¦¬ν•˜λ„λ‘ ν•˜λŠ” 것을 지ν–₯ν•˜λŠ”λ°μš”,
F#μ—μ„œλŠ” 이것을 μœ λ‹ˆμ˜¨ νƒ€μž…μœΌλ‘œ ν•΄κ²°ν•©λ‹ˆλ‹€.

3 Likes