2014년 12월 23일 화요일

애플의 새로운 개발언어 Swift - 함수#10

// Playground - noun: a place where people can play

import UIKit

func doSomething() {
    println("기본적인 함수의 형태")
}

//함수 호출
doSomething()

//리턴값이 있는 함수
func doSomething2() -> String {
    return "something fun to do on Swift"
}

doSomething2()

//변수 파라메터 
func square(var num: Int) -> Int {
    return num*num
}

square(2)

//파라메터가 2 이상인 경우
func add(a:Int, b:Int) -> Int {
    return a+b
}

add(1, 2)

//튜플을 리턴
//가독성을 위해 튜플의 이름을 지정하는 습관을 가지는 것이 좋다
func fetchName(id:Int) -> (statusCode:Int, name:String) {
    var code = 200
    var fetchedName = "James"
    return (code, fetchedName)
}

var result = fetchName(123)
println(result.statusCode)
println(result.name)

//옵셔널 튜플을 리턴하는 경우 
//(statusCode:Int, name:String)? 이렇게 표기하면 nil 리턴될 있다
//그러나 (Int?, String?) 같이 선언된 튜플은 개별 요소가 nil 있지만 
//튜플 전체가 nil 없다.
func fetchName2(id:Int) -> (statusCode:Int, name:String)? {
    if id <= 0 {
        return nil
    }
    
    var code = 200
    var fetchedName = "James"
    
    return (code, fetchedName)
}

if let result = fetchName2(123) {
    println(result.statusCode)
    println(result.name)
}

// Playground - noun: a place where people can play

import UIKit

//두개의 값을 교환하는 함수
//정상적으로 처리되지 않는다
func swapNumbers(var a:Int, var b:Int) {
    let tmp = a;
    a = b;
    b = tmp;
}

var foo = 10
var bar = 20

swapNumbers(foo,bar)

println(foo)
println(bar)

//이번에는 입출력 파라메터로 구현해 본다.
//입출력 파라메터는 몇가지 제약을 가지고 있다. 입출력 파라메터는 기본값을 가질 없고
//가변인자 파라메터를 입출력 파라메터로 선언할 없다
//그리고 inout, var, let 파라메터 선언시 서로 베타적이기 때문에 동시에 사용할
//없다.
func swapNumbers2(inout a:Int, inout b:Int) {
    let tmp = a;
    a = b;
    b = tmp;
}

var foo2 = 10
var bar2 = 20
swapNumbers2(&foo, &bar)
println(foo)
println(bar)

//함수 형식을 사용한 계산기 
//닷넷의 델리게이트와 같은 개념(Function Type-함수 형식)
//C언어의 함수 포인터와 동일하다.
//1)우선 사칙 연산을 위한 4개의 함수를 정의한다. 비슷한 모양이다.
func add(a:Int, b:Int) -> Int {
    return a+b
}
func subtract(a:Int, b:Int) -> Int {
    return a-b
}
func multiply(a:Int, b:Int) -> Int {
    return a*b
}
func divide(a:Int, b:Int) -> Int {
    return a/b
}

//2)어떤 함수들인지 형태를 지정한다.
var f:((Int, Int) -> Int)? = nil
var op = "+"
switch op {
    case "+":
        f = add
    case "-":
        f = subtract
    case "*":
        f = multiply
    case "/":
        f = divide
    default:
        break
}
//3)아래와 같이 호출한다.
if f != nil {
    var result = f!(2,3)
    println("2 \(op) 3 = \(result)")
}

//함수 형식을 파라메터로 전달
func processResult(function:(Int, Int) -> Int, a:Int, b:Int) {
    println("Result: \(function(a,b))")
}

var f2:((Int, Int) -> Int)? = nil
var op2 = "*"
switch op2 {
case "+":
    f2 = add
case "-":
    f2 = subtract
case "*":
    f2 = multiply
case "/":
    f2 = divide
default:
    break
}

if f2 != nil {
    processResult(f2!, 20, 3)
}

//함수 형식을 리턴하는 함수 
//함수 선언에 포함된 첫번째 리턴 화살표는 항상 함수의 파라메터와 리턴형을 구분하는 역할을 한다.
func select(op:String) -> ((Int, Int) -> Int)? {
    switch op {
        case "+":
            return add
        case "-":
            return subtract
        case "*":
            return multiply
        case "/":
            return divide
        default:
            return nil
    }
}

var op3 = "+"
var f3:((Int,Int) -> Int)? = select(op3)

if f != nil {
    processResult(f3!, 2, 3)
}


// Playground - noun: a place where people can play

import UIKit

//내포된 함수(Nested Function)
//앞에서 살펴본 함수는 전역 공간에 선언된 전역 함수들이다
//전역 함수는 코드의 가독성이 떨어지고 객체지향의 특징인 은닉을 만족시키지 못한다
//코드의 규모가 커지면 커플링이 심해지고 쓰레드의 안정성이 떨어질 있다
//아래와 같이 내포된 함수(add, subtract, multiply, divide) 기본적으로
//select함수 내부에서만 인식되고 호출될 있다
//하지만 select함수와 같이 함수형을 리턴하는 경우에는 호출자가 포함된 공간으로
//사용 범위가 확대된다.
func select(op: String) -> ((Int, Int) -> Int)? {
    func add(a:Int, b:Int) -> Int {
        return a+b
    }
    func subtract(a:Int, b:Int) -> Int {
        return a+b
    }
    func multiply(a:Int, b:Int) -> Int {
        return a+b
    }
    func divide(a:Int, b:Int) -> Int {
        return a+b
    }
    
    switch op {
        case "+":
            return add
        case "-":
            return subtract
        case "*":
            return multiply
        case "/":
            return divide
        default:
            return nil
    }
}

var op = "+"
var f:((Int, Int) -> Int)? = select(op)

if f != nil {
    println("Result: \(f!(2,3))")
}

//커링 함수: 커링(Currying) 여러개의 파라메터를 가진 함수를 하나의 파라메터를 가진 여러 함수로 분리하는
//프로그래밍 기법이다. 실행에 따라 변경되는 일부 파라메터를 나중에 전달할 있어 함수를 객체처럼 추상화 있다
// 기법의 명칭은 수학자인 헤스켈 커리의 이름에서 유래했다
//커리드 함수는 하나의 파라메터를 전달받아 함수를 리턴한다. 리턴된 함수는 커리드 함수 체인에 있는
//다음 파라메터를 전달받고 다른 함수를 리턴한다
func add(a:Int, b:Int) -> Int {
    return a+b
}
func addCurried(a:Int) -> (Int -> Int) {
    func addInternal(b:Int) -> Int {
        return a+b
    }
    return addInternal
}
var result = addCurried(1)(2)
println(result)












2014년 12월 22일 월요일

애플의 새로운 개발언어 Swift - 반복문과 제어문 #9

// Playground - noun: a place where people can play

import UIKit

//for문에서 {} 생략할 없는 것에 주의한다.
var str = "Swift"
for ch in str  {
    println(ch)
}

var total = 0
var num = 1

while num <= 100 {
    total += num++
}

println("total: \(total)")

//if문에서 조건식을 감싸는 괄호는 제거되었고 {} 반드시 있어야 한다
var password = "1234abcde"
var specialCharSet = NSCharacterSet.symbolCharacterSet()

if countElements(password)<8 {
    println("password too short")
}
else if password.rangeOfCharacterFromSet(specialCharSet) == nil {
    println("password must have symbol char")
}
else {
    print("password is valid")
}

import Foundation
//switch Swift에서 break 사용하지 않는다
//Objective-C에서는 정수만 비교 가능했지만 지금은 정수, Double, String 가능하다.
var textAlignment = NSTextAlignment.Center

switch textAlignment {
case NSTextAlignment.Left:
     println("left")
case NSTextAlignment.Center:
     println("center")
case NSTextAlignment.Right:
     println("right")
default:
     println("default")
}

//Objective-C 폴쓰루를 지원한다
//비슷하게 Swift에서 구현하려면 아래와 같이 한다
var textAlignment2 = NSTextAlignment.Left

switch textAlignment2 {
case NSTextAlignment.Left:
    println("left")
    fallthrough
case NSTextAlignment.Center:
    println("center")
    fallthrough
case NSTextAlignment.Right:
    println("right")
    fallthrough
default:
    println("default")
}

//문자열 매칭 
//switch구문에서 대소문자를 구분하는 것에 주의한다.
var vendor = "apple"
switch vendor {
    case "APPLE":
        println("iMac")
    case "apple":
        println("iPhone")
    case "google":
        println("Android")
    case "ms":
        println("Windows Phone")
    default:
        println("others...")
}

//튜플 매칭
// _ 사용하면 특정 요소를 패턴 매칭에서 제외할 있다.
var diff = (0, 32)

switch diff {
case (0,0):
    println("no move")
case (_,0):
    println("move horizontally")
case (0,_):
    println("move vertically")
default:
    println("outside screen")
}

// 바인딩을 사용하는 경우
//_문자는 튜플의 특정 요소를 무시하기 때문에 케이스 구문 내부에서 사용하려면
//임시 상수로 대치할 있다
//임시 상수로 대체된 요소는 패턴 매칭에서 제외되지만 요소가 가진 
//값은 임시 상수에 할당되므로 case 내부에서 사용할 있다
//이러한 방식을 바인딩(value binding)이라고 한다.
var diff2 = (30, 0)
switch diff2 {
case (0,0):
    println("no move")
case (let x, 0):
    println("move horizontally: \(x)px")
case (0, var y):
    println("move vertically: \(y)px")
default:
    println("move diagonally")
}

// 바인딩 시에는 default 생략할 있다. 원래는 안되지만 
//이유는 switch 마지막 부분에 바인딩을 통해 앞에서 일치하지 않는 
//모든 패턴을 매칭시킬 있는 case 제공하기 때문이다
var diff3 = (30, 20)
switch diff3 {
case (0,0):
    println("no move")
case (let x, 0):
    println("move horizontally: \(x)px")
case (0, let y):
    println("move vertically: \(y)px")
case (let x, let y):
    println("move \(x)x\(y)")
}

//왼쪽과 오른쪽 방향 구분 
var diff4 = (30, 0)
switch diff4 {
case (0,0):
    println("no move")
case (let x, 0):
    if x<0 {
        println("move left: \(x)px")
    } else {
        println("move right: \(x)px")
    }
case (0, let y):
    println("move vertically: \(y)px")
default:
    println("move diagonally")
}

//조건을 상세하게 지정하는 where 
var diff5 = (30, 0)
switch diff4 {
case (0,0) where diff5.0 < 0:
    println("no move")
case (let x, 0) where x < 0:
    println("move left: \(x)px")
case (let x, 0) where x > 0:
    println("move right: \(x)px")
default:
    println("move diagonally")
}

//새로 도입된 범위 연산자를 사용하는 경우 
var count = 50
switch count {
case 1..<10:
    println("small box")
case 10...30:
    println("medium box")
case 31...100:
    println("big box")
default:
    println("not available")
}

//중첩된 for 반복문 
for outerNum in 1...10 {
    for innerNum in 1...10 {
        if innerNum > 5 {
            break
        }
        println("inner: \(innerNum)")
    }
    println("outer: \(outerNum)")
}

//라벨을 붙여서 사용하는 경우
//바깥쪽 라벨을 지정해서 탈출하기 때문에 5번만 반복하고 종료된다.
OUTER_LOOP: for outerNum in 1...10 {
    INNER_LOOP: for innerNum in 1...10 {
        if innerNum > 5 {
            println("END OUTER")
            break OUTER_LOOP
        }
        println("inner: \(innerNum)")
    }
    println("OUTER: \(outerNum)")
}


요즘 많이 들리는 RAG에 대한 멋진 정리가 있어서 공유합니다. ㅎㅎ

 작년에는 ChatGPT가 크게 유행을 했는데 올해는 Gen AI, LLM, 랭체인등이 유행하고 있습니다. ㅎㅎ  RAG라는 단어도 상당히 많이 들리고 있습니다. 멋진 정리의 링크입니다.  https://brunch.co.kr/@ywkim36/146?...