Factor로 첫 문제 풀이

15 views
Skip to first unread message

디토

unread,
Feb 13, 2009, 11:21:52 PM2/13/09
to factor-kr
Project Euler의 2번 문제(Find the sum of all the even-valued terms in the
Fibonacci sequence which do not exceed four million.)를 Factor로 풀어봤습니다.
코드 리뷰 부탁해요~ (다른 방법을 알려주실 필요는 없어요. 같은 알고리즘을 유지하면서)

: limit? ( x -- ? ) dup 4000000 > ;
: next ( x y -- y z ) tuck + ;

{ } 1 2 [
dup even? [ rot over suffix -rot ] [ ] if
next limit? not
] loop
2drop sum .

아직까지 값을 세개 이상 조작하는 shuffle word는 못 외우겠더군요. tuck 같은 단어는 그냥 봐서는 감이 잘 안 오
는;;

그리고 스택 변화 추이는 이런 식으로 적으니까 생각하기 좋더라고요.
seq x y -- x y seq -- x y seq y -- x y seq -- seq x y

디토

unread,
Feb 14, 2009, 12:00:03 AM2/14/09
to factor-kr
점심 먹으면서 생각해보니까 필요 없는데 괜히 배열을 썼더라고요. 그래서 배열 안쓰게 수정~

On 2월14일, 오후1시21분, 디토 <dit...@gmail.com> wrote:
> { } 1 2 [
> dup even? [ rot over suffix -rot ] [ ] if

> ...
> 2drop sum .

대신에

0 1 2 [
dup even? [ rot over + -rot ] [ ] if
...
2drop .

한결 간단해졌네요.

Jong-Hyouk Yun

unread,
Feb 14, 2009, 1:12:20 AM2/14/09
to fact...@googlegroups.com
오... 실제로 적용해서 해보고 계시군요?

코드리뷰는 서로 용기가 필요하죠. ^^;

새로운 paradigm에 적응하시려는 노력이 보이니다. ^^

간단히 limit? 워드는 굳이 그 안에서 dup하지 않는게 맞지 않을까요?
(기본적으로 모든 word은 consume을 하죠. 굳이 consume하고 싶지 않을때는 명시적으로 dup하죠.)

그리고 stack-infer도 틀린것 같애요. (컴파일 해보시고 :errors을 쳐보시면 실제 decalred된
stack효과가 ( x -- x ? )인걸 확인하실수있어요)

제 생각엔 stack-shuffler와 친숙해지는것도 중요하지만
locals등을 이용해서 정리하는게 필요할것 같아요.

걔네들이 이미 저런 tuck, rot, rot-같은 복잡한 shuffler을 이용해 쌓아올린 추상화단계거든요.


아-_- 저도 저 코드는 한눈에 못알아보겠는데요.

팩터의 목적은 obfuscated, esoteric한 코드를 만드는데 있지않고 간결하고 깔끔한 코드를 작성하는데 있다고 생각해요.


첫술에 배부를수 없고, 앞으로 계속해서 적응해 가실거고 (저도 훌륭한 코드를 작성하지는 못하지만요) 하지만 대략 팩터
커뮤니티에서는 다음과 같은 방향으로 발전해 나가는걸 권장하더라구요.


1. word의 이름은 명시적으로 작성하자.
next --> next-fib-n이라던지 word이름만으로 유추하기 쉬운 이름이 더 좋겠죠.
factor에서는 이름규칙이 상대적으로 자유롭고, 훨씬 자유롭게 설명적인 이름을 붙이는걸 권장해요.


2. 스택을 자료구조로 쓰는걸 지양.
제 생각엔 array나 sequence을 이용하는게 맞는것 같아요.
스택을 배열처럼 이용하는 스타일은 당연히 스택효과가 복잡해지고,
복잡한 스택조작에 의존할수밖에 없겠죠.
그리고 결과적으로 코드는 이해하기 힘들고 작은 워드들로 분리하기도 힘들어지죠.
분명히 배열의 맨끝의 요소만을 꺼내거나 하는 워드들이 이미 존재하니까 그런걸 살펴서 적용해보시는게 어떨까요?


3. 하나의 워드는 가능하면 짧게, 하나의 일만 잘하도록
유닉스의 철학처럼, 하나의 워드가 하나의 일을 잘하도록 분리하고
다른 워드와 연동을 잘할수있도록 만드는게 중요하다고 생각합니다.
(유닉스에서 개별적인 프로그램이 서로 파이프등을 통해서 서로 연동하고 조합할수있듯이)


4. 하나의 워드에서 여러개의 값을 이용해야 한다면, locals을 이용해서 명확하게.
전형적으로 하나의 값이 한 워드의 여러부분에서 나타난다면 스택에 dup하고 tuck하고 복잡하겠죠?
예를들어, 어떤수의 약수들을 구하는 word은 다음처럼 정의할수있겠죠

USING: math.ranges sequences ... ;
:: divisors ( n -- seq )
n [1,b] [ n swap mod 0 = ] filter ;

'::' 선언은 ':'워드와 같지만 내부적으로 '[let'워드를 통해서 local 바인딩을 만들어주죠. 다음의 축약형인거죠

: divisors ( n -- seq )
[let | n [ ] |
n [1,b] [ n swap mod 0 = ] filter ] ;

5. 가능하면 루프나 제어구조 대신에 functional한 스타일의 코드를.

loop을 이용하는것도 좋겠지만 math.ranges을 통해서 파이썬의 for ... in range(...):와 같이 범위에
따른 루프를 구성하거나 하는게 가능하겠죠?

아... 뭔가 적어보니 많은걸요;

근데 저도 전에 처음에 제가 작성했던 같은 문제의 코드를 보니까 정말 부끄럽네요;;; 남보고 뭐라할 처지가;;;

그런데 확실히 많은 코드를 작성할수도록 스타일도 좋아지고, 익숙해지더라구요. :-)

좋은하루되세요!

2009년 2월 14일 (토) 오후 2:00, 디토 <dit...@gmail.com>님의 말:

Jong-Hyouk Yun

unread,
Feb 14, 2009, 1:19:49 AM2/14/09
to fact...@googlegroups.com
6. 그리고 vocab으로 분리해서 프로그램을 작성하고, unit-test을 활용하시길. project-euler의 문제들은
단위테스트를 적용하기 좋은예라고 생각해요.

http://docs.factorcode.org/content/article-first-program.html

보셨겠지만 이 튜토리얼을 따라서 vocab으로 프로그램을 만들고, 단위테스트를 적용해나가는걸 아실수있어요.

그리고 마지막으로 http://paste.factorcode.org/ 에 코드를 올려주시는것도 좋을듯.

예를 들어, 제 euler.002은 다음과 같애요.

(math.fibonacci, sequences.last vocab을 추가적으로 만들어서 해결했었어요.
나중에 알고보니까 sequences.last은 단순히 head, tail등을 이용하면 되겠더라구요.)

http://paste.factorcode.org/paste?id=433

euler.002의 solve워드를 실행하면 그냥 화면에 찍어주죠.

워드의 내용을 가능하면 영어문장처럼 주욱 읽어나가면 그 설명이 되는 방향으로 작성하도록 저는 노력했었어요. (스택조작이나
그런거보다 그런거에 관심이 많았어요.)

그럼 해피 factor-ing!


2009년 2월 14일 (토) 오후 3:12, Jong-Hyouk Yun <agel...@gmail.com>님의 말:

Jong-Hyouk Yun

unread,
Feb 14, 2009, 9:34:22 PM2/14/09
to fact...@googlegroups.com
http://paste.factorcode.org/paste?id=435

하악 하악 멋진 코드!


2009년 2월 14일 (토) 오후 3:19, Jong-Hyouk Yun <agel...@gmail.com>님의 말:

Reply all
Reply to author
Forward
0 new messages