PL λαβ

Lab 3.1a[김예령]: 람다와 클로저 본문

kos

Lab 3.1a[김예령]: 람다와 클로저

IC4RUS 2021. 4. 29. 18:11

Comment

www.lwh.jp/lisp/lambda.html 페이지를 참고하여 C코드를 Python코드로 포팅한다는 느낌으로 만들었습니다.

차근차근 따라하다보니 개념은 이해가 되었지만 lambda가 한번 나오는 것이 아닌 여러번 나오는 문장을 해석하는 방법에 대해서는 아직 고민중이라 완성된 코드는 아닙니다. lambda의 cdr이 lambda면 다시 재귀하는 방법을 취해야할 것 같습니다.

만들다보니 신기하네요 람다의 세계는

 

Code

바뀐 부분의 코드만 기재하였습니다.

...

def env_get(env, symbol):
    parent = env.parent

    if symbol.value.upper() in env.symbols:
        return env.symbols[symbol.value.upper()]

    if type(parent) is Bindings:
        pass
    elif isNil(parent):
        return "Error unbound", nilp()

    return env_get(parent, symbol)

...

def eval_expr(expr, env):
    if expr.type == Type.SYM:
        return ErrorType.ERROR_OK, env_get(env, expr)
    elif expr.type != Type.PAIR:
        return ErrorType.ERROR_OK, expr

    if not listp(expr):
        return ErrorType.ERROR_SYNTAX, nilp()

    op = expr.car()
    args = expr.cdr()

    if op.type == Type.SYM:
        env_val = env_get(env, op)

        if op.value.upper() == "QUOTE":
            if isNil(args) or not isNil(args.cdr()):
                return "Error_Args", nilp()
            return "Error_OK", args.car()
        elif op.value.upper() == "DEF":
            if isNil(args) or isNil(args.cdr()) or not isNil(args.cdr().cdr()):
                return "Error_Args", nilp()
            sym = args.car()
            if sym.type != Type.SYM:
                return "Error_Type", nilp()
            err, val = eval_expr(args.cdr().car(), env)

            env_set(env, sym, val)
            return "Error_OK", sym
        elif op.value.upper() == "LAM":
            if isNil(args) or isNil(args.cdr()):
                return "Error_Type", nilp()
            # 여기에 env set해줘야하나 mk_closure에서 해줘야하나 -> mk_closure에서

            return mk_closure(env, args.car(), args.cdr())
        # elif env_val and env_val.type == Type.BUILTIN:
        #     return apply(env_val, args)
    err, op = eval_expr(op, env)
    # if err:
    #     return err
    args = copy_list(args)
    p = args
    while not isNil(p):
        err, p.value[0] = eval_expr(p.car(), env)
        # if err:
        #     return err
        p = p.cdr()
    return apply(op, args)

    return "Error_Syntax", nilp()

...

def apply(fn, args):
    if fn.type == Type.BUILTIN:
        return "Error OK", fn.value(args)
    elif fn.type != Type.CLOSURE:
        return "Error_Type", nilp()

    env = env_create(fn.car())
    params = fn.cdr().car()
    body = fn.cdr().cdr()

    while not isNil(params):
        if isNil(args):
            return "Error_Args", nilp()
        env_set(env, params.car(), args.car())
        params = params.cdr()
        args = args.cdr()

    if not isNil(args):
        return "Error_Args", nilp()

    while not isNil(body):
        result = eval_expr(body.car(), env)
        body = body.cdr()

    return "Error_OK", result

...

def mk_closure(env, params, body):
    if not listp(params) or not listp(body):
        return "Error_Type", nilp()

    p = params

    while not isNil(p):
        if p.car().type != Type.SYM:
            return "Error_Type", nilp()
        p = p.cdr()

    result = cons(env, cons(params, body))
    result.type = Type.CLOSURE

    return "Error_OK", result

 

Test

# Test 01
>> (define square (lambda (x) (* x x)))
('Error_OK', square)
>> (square 3)
('Error_OK', ('Error OK', ('Error OK', 9)))

# Test 02
>> ((lambda (x) (- x 2)) 7)
('Error_OK', ('Error OK', ('Error OK', 5)))

# Test 03
>> (define make-adder (lambda (x) (lambda (y) (+ x y))))
('Error_Args', NIL)

# Test 04
>> (define sq-two (square 2))
('Error_Args', NIL)

Test 01과 02와 같이 lambda - arg - body 구조는 분석이 정상적으로 됩니다.

하지만 Test 03처럼 lambda의 body에 lambda가 나타나는 경우 분석하지 못하고

Test 04처럼 body에 함수가 들어가는 경우도 분석하지 못합니다.

'kos' 카테고리의 다른 글

Lab 4.1a[최준혁]: 조건, 비교  (0) 2021.05.02
Lab 4.1a[김예령]: 조건, 비교  (0) 2021.04.29
Lab 3.1a[최준혁]: 람다와 클로저  (0) 2021.04.27
Lab 2.2b[김예령]: 기본 함수  (0) 2021.04.27
Lab 3.1: 람다와 클로저  (0) 2021.04.27
Comments