posted by 아겔-_- 2009.04.11 16:19
이전 '다양한 클래스 선언'에서 믹스인에 대해서 설명했었음.

믹스인은 유니온과 유사하지만, 어떤 범주가 되는 클래스에 계속해서 다른 클래스를 추가해넣을수있음.

팩터는 단일상속이지만, 어떤 객체나 클래스는 다른 클래스에 속하거나 할 수 있는 '관계'를 지정할있으므로 이런것이 가능.

프로토콜 슬롯은 이러한 믹스인을 이용하여 다른 언어에서 프로토콜이나 인터페이스처럼 특정한 '규약'을 클래스가 준수함을 표현.

  1. MIXIN:으로 믹스인 클래스를 선언한다.
  2. SLOT: 선언으로 공유할 슬롯을 선언한다.
  3. 믹스인을 구현할 클래스에서 SLOT: 선언에 해당하는 슬롯들을 구현한다
  4. 믹스인을 구현한 클래스를 INSTANCE:을 이용하여 믹스인에 추가한다.

은근히 이런식으로 구현한 클래스들이 팩터에 많은듯. (시퀀스 프로토콜, growable 프로토콜...)

그리고 믹스인과 슬롯의 구분이 분리된듯한데 이럴때는 사실 PROTOCOL: 선언을 통해서 프로토콜의 이름과 그 프로토콜이 구현하기를 원하는 word들을 나열하고 이를 구현하는것으로 대신할수있다. (자세한것은 delegates을 참고)



신고
posted by 아겔-_- 2009.04.11 16:01
객체의 동일성 판별은 기본적으로 다음의 워드들을 이용한다.

  • eq? : 두 객체가 완전히 같은 객체의 참조인지를 판별
  • = : 두 객체가 같은 클래스, 같은 슬롯값을 갖는지를 갖고 판별 (실제 참조가 다르더라도)

그리고 number 클래스의 값들은 서로 다른 범위(실수, 정수...)에 속하더라도 같은 값인지를 판별하려면 "number="을 이용한다.

또한, 직접 객체의 유일성을 구현할 경우에는 해당 클래스에 대한 equals? 제네릭을 구현하면된다.

(객체의 유일성을 판별하는 테스트를 작성하고 싶으면 dup, clone 워드를 이용해서 참조의 복사, 객체의 복제를 하면된다.)


어떤 클래스의 인스턴스들이 값에 의해서 서로 대소관계를 가지면 "linear order protocol"을 구현하면 된다.

기본적으로 두 객체에 대해서 <=> 워드를 적용하면 대소판별의 결과를 (좌변을 기준으로) 심볼로 되돌립니다. (+lt+, +gt+, +eq+)

어떤 사용자 클래스가 대소비교를 적용해야할 경우에는 (정렬등을 적용하려면 그래야겠죠?) 단순히 <=> 제네릭을 구현합니다.

프로토콜에 대해서는 이후에 다시 설명하겠습니다.
신고
posted by 아겔-_- 2009.04.06 00:52
팩터는 단순히 상속, 구현이외에 클래스간의 관계를 집합논리에 따라 설정할수있음. 다른 언어의 객체시스템들과는 전혀 다르면서도 매우 유연한 객체시스템을 제공.

우선 가볍게 간단한 싱글턴부터.

( scratchpad ) SINGLETON: foobar
( scratchpad ) GENERIC: do-foo ( obj -- )
( scratchpad ) M: foobar do-foo ( obj -- ) drop "THIS IS FOOBAR!" . ;
( scratchpad ) foobar do-foo
"THIS IS FOOBAR!"
"foobar" 클래스를 만들고, 싱글턴이니까 인스턴스에 대한 정의도 필요없이 그냥 클래스 자체에 메서드를 붙이는것을 볼수있음.

predicate, union, intersection은 기존의 클래스에 다른 '범주'를 추가하는것으로 생각할수있음. 이들로 선언한것들도 일반적인 클래스와 동일하게 취급.

predicate은 기존의 클래스로부터 특정 조건을 만족하는 인스턴스를 새로운 'predicate class'에 속하는것으로.

( scratchpad ) \ even? see
IN: math
: even? ( n -- ? ) 1 bitand zero? ;

( scratchpad ) PREDICATE: even-p < number even? ;
( scratchpad ) 4 even-p? .
t
( scratchpad ) 9 even-p? .
f
"PREDICATE: class < superclass predicate... ;"로 선언했음. "even?" 워드를 predicate로 사용하고 number 클래스의 인스턴스들 중에서 짝수인것들을 even-p 클래스로 선언했음. 그리고 간단히 even-p 클래스가 선언되면서 자동적으로 생긴 "even-p?" 워드를 이용하여 클래스에 속하는지를 판별.

여기서 볼수있듯이 단순히 type-hierarchy에 속할때만이 아니라, 동적으로 어떤 인스턴스가 어떤 클래스에 속하는지 판별이 가능하다는것을 알수있음.

union은 클래스들을 하나로 묶어 공통된 클래스에 속하는것으로 이미 존재하는 클래스들에 대해 적용한다.

( scratchpad ) SINGLETON: apple
( scratchpad ) SINGLETON: strawberry
( scratchpad ) SINGLETON: pear
( scratchpad ) SINGLETON: carrot
( scratchpad ) UNION: fruits apple pear ;
( scratchpad ) UNION: vegetables strawberry carrot ;
( scratchpad ) strawberry fruits? .
f
( scratchpad ) strawberry vegetables? .
t
( scratchpad ) apple fruits? .
t
( scratchpad ) apple vegetables? .
f



mixin은 union과 같이 클래스들을 하나의 범주로 묶는데, 이후에 계속해서 해당 범주에 클래스들을 추가해나가는것이 가능하다. (다른 언어의 '믹스인'들과 좀 다름)

( scratchpad ) MIXIN: talking
( scratchpad ) MIXIN: flying
( scratchpad ) SINGLETON: dragon
( scratchpad ) INSTANCE: dragon talking
( scratchpad ) INSTANCE: dragon flying
( scratchpad ) SINGLETON: beaver
( scratchpad ) INSTANCE: beaver talking
( scratchpad ) beaver flying? .
f
( scratchpad ) beaver talking? .
t
( scratchpad ) dragon [ flying? ] [ talking? ] bi
--- Data stack:
t
t

정말 다른 언어에서 믹스인처럼 공통적인 behavior을 공유하고자 한다면, 단순히 MIXIN클래스에 메서드를 붙이는것으로 똑같이 할수있음.


intersection은 이렇게 유니온이나 predicate등으로 선언한 클래스를 어떤 '조건'이나 범주로 보았을때 그러한 조건들을 모두 충족하는 '교집합'에 속하는 인스턴스의 클래스를 선언할때 사용함.

( scratchpad ) SINGLETON: male
( scratchpad ) SINGLETON: female
( scratchpad ) UNION: gender male female ;
( scratchpad ) TUPLE: person age sex ;
( scratchpad ) PREDICATE: young-person < person age>> 30 < ;
( scratchpad ) PREDICATE: woman < person sex>> female = ;
( scratchpad ) INTERSECTION: young-girl young-person woman ;
( scratchpad ) 17 female person boa
--- Data stack:
T{ person f 17 female }
( scratchpad ) young-girl? .
t
( scratchpad ) 28 male person boa young-girl? .
f







신고
posted by 아겔-_- 2009.03.30 00:12

팩터에서 모든것은 객체다.

모든것이 객체라는 선언이 별다를것도 없다고 생각할 수 있지만, 요즘 세상에서 화두가 되는 몇가지를 생각해보자.

스몰톡, 루비, Io와 같은 언어들에서는 모든것이 객체다. 이런 언어에서 모든 primitve들도 모두 객체를 다루듯이 메시지를 보내고, 자유롭게 변수에 할달하고한다. 심지어 객체라고 생각하기 힘든것들도 객체로 표현한다. 코드, 코드블럭, 메서드, 클래스, 메타 클래스, 메시지, 심지어 코드의 실행상태(continuations)까지.

그러면 그렇지 않은것은 뭘까? 모든것이 객체가 아닌것? 그게뭐지? 그건 좀 아닌것 같은데. 조금 범위를 좁혀보면, "몇몇것은 객체가 아닌것"이라고 생각할수있겠다.

자바와 C#은 객체지향언어임에는 변함이 없겠지만 몇몇은 객체가 아니다.(혹은 아니었다.) 자바에서 "int x"와 "Integer x"은 서로 다르다. 컴파일러와 API적인 지원으로 갭을 메우지만, 여전히 서로 다른것으로 취급함을 주의해야하고 boxing/unboxing이 '세심한 배려'라고 그냥 생각하며 사용하는게 속편하다.

"모든것이 객체"라는 명제가 객체지향에만 국한되는것은 아닌것 같다.(조금 뜬금없을수도있고, 결벽적으로 접근한다면 다른 영역에 해당할수도있겠지만)

값(value)을 다루는 방법에 대한것이기도 하다고 생각한다.

예를 들어, 스킴(Scheme)에서 객체지향에 대한 지원이 없더라도(클래스를 만들고, 인스턴스를 만들고 메서드를 구현하고...), 분명 그 언어에서는 다양한 타입(클래스)의 객체를 지원한다.(벡터, 문자, 정수, 함수...) 그리고 이런 객체(값)들은 모두 하나의 방법을 통해서 변수에 대입할수있고 모두 똑같은 방식으로 그 변수에 접근할수있음을 생각해보자. (굳이 스킴이 아니라고 하더라도.)

서론이 길었다. 팩터에서는 양쪽 모두에 해당한다.

모든값은 어떤 클래스에 속하고, 상속이 가능하며, 추가적인 메서드를 붙이거나 할 수 있는 '객체'이고, 모든 객체들은 동일한 방법으로 접근이 가능하다.




신고
posted by 아겔-_- 2009.03.21 14:00
그간 Slava가 new_ui에 대한 작업을 해온건 알고 있었고, 원래 유니코드를 완전히 지원하는 언어이고, 한글 인코딩에 대해서는 제가 지원을 했기 때문에 "설정이 제대로 되있다면" 이맥스+FUEL등에서 한글을 입력하고 출력하는게 팩터에서 가능함을 잘알고 있었습니다.

그런데 한국인으로서 딱하나 팩터를 사용하는데 좀 거시기한 부분도 팩터의 UI에서 유니코드 입출력이 안되던점이었는데요. 이번 new_ui을 도입하면서 pango을 이용하여 완전히 유니코드 출력이 가능해졌고, 한글입력은 Win32에서 테스트해본 결과 특별한 작업이 없이도 잘 굴러감을 확인했습니다. :-)

아직 윈도용 official-binary은 2009/02/23으로 new_ui을 지원하지 않고 있습니다. 윈도에서는 tools.disassembler가 정상적으로 단위테스트를 통과하지 못해서라고 하네요. 해당 부분을 제외하고는 사용이 충분히 가능한 상태라고 하기에, 

1. cygwin에서 git pull한 다음에 
2. 'make'으로 vm을 만들고
3. bootstrap이미지를 받아서 "./factor.com -i=boot.image"로 부트스트래핑...
4. 그리고 마지막으로 build-supports/dlls.txt에 필요하다고 적힌 dll들을 찾아다 팩터와 같은 디렉토리에 복사. (전부 cairo, pango, libpng, libtiff, zlib 같은 기본적인것들이라 GIMP-win32을 설치한 디렉토리를 찾아보면 나오더라구요.)
5. 그리고 즐거운 팩터링!


또, 리눅스랑 Cocoa에서는 아직 제가 테스트를 못해봤습니다. (출력은 아마 정상이겠고, 둘 다 IME에 대한 지원 코드가 있다고 Slava가 그러더군요. 그래서 아마 잘 굴러가지 않을까 하는 중.)



가젯(팩터의 UI프레임웍)을 이용해서 한글을 넣어도 잘되더군요. (당연히 팩터 UI리스너가 가젯으로 되어있으니^^;)

하여튼 더 깔끔해지고, UI체감속도도 훨씬 원할해졌고 좋아졌네요.



ps. 바이너리 필요하신분 계시면 배포할까요?

신고
posted by 아겔-_- 2009.02.23 23:12
2009/2/22 팩터 바이너리를 받아 실행해보니 적용이 잘되어있네요. 

간단히 작성한 문서도 잘 포함이 되있구요. 

new_ui에 대한 작업이 어느정도 이루어지면 한글출력도 팩터ui에서 가능할걸로 보입니다. (pango backend) 그리고 추가적으로 win32, cocoa, x11에서 입력기에 대한 지원을 더하면 완전한 한글환경을 갖출것으로 생각됩니다. :-) 


ㅋ... 매일 매일이 설레고 즐겁군요. :-)
신고
posted by 아겔-_- 2009.02.21 02:19
Imperative Factor

Imperative Factor

  • 이 문서는
    • 팩터에서 imperative한 스타일의 코드 작성에 관한 정리
    • 작성
      • 아겔-_- <ageldama@gmail.com>
      • 2009년 2월 20일 금요일
  • 지역변수, lambda, mutable한 변수
    • locals vocab을 이용해서 lisp, ml, haskell와 유사한 let-binding을 이용할수있어요
    • lexically scoped
    • [let | n [ 40 ]
             m [ 2 ] |
            n m + . ]
      • [let 워드로 시작해서 | .. | 사이에 [let ... ] 사이의 quotation에서 이용할 바인딩들을 선언해요
      • n [ 40 ] 처럼 변수의 이름과 다음 quotation에 그 값을 적어줘요
      • lisp에서의 let와 같이 바인딩끼리 참조는 안되요
        • 서로 참조하기 위해서 [let*을
    • [let* | a [ 40 ]
               b [ 2 ]
               the-answer [ a b + ] |
             the-answer . ]
      • the-answer은 같은 바인딩에 있는 a와 b을 참조해서 산출
    • [wlet | inc1 [ 1+ ] | 2 inc1 . ]
      • lisp에서의 flet과 같은 역활
      • [let, [let* 워드은 그 형식이 값에 대해서 quotation의 형식을 취하기 때문에 quotation 그 자체를 바인딩하고 싶을때는 [wlet 워드를 쓰는게 더 편리
      • 물론 [let을 이용해서 [ [ 1+ ] ]이렇게 quotation을 중첩해서 표현해도 되지만 뭔가 자연스럽지 않으니까 (호출시 용법도 복잡하구)
      • [let*처럼 같은 바인딩의 함수끼리 재귀적으로 선언은 못한다는 약간의 제약이 있음
    • [| .. | ... ]을 이용하거나 :>을 이용해서 클로져를 만들수있어요
      • [| a b | a b * ]
        • 스택에서 a b을 취해서 그 맨 안에서 a b *의 형식으로 이용이 가능한 quotation을 만들죠
        • 3 4 [| a b | a b * ] call .
          • 화면에 12을 찍겠죠
      • [ :> a :> b a b * ]
        • 위와 같은데 ":> word"의 형식으로 현재 스택의 한 값을 바로 word에 바인딩해주죠
        • 주) 람다클로져 안에서만 사용이 가능하니 사실 별효용은 없는것 같지만, 람다에서 문맥중에 갑자기 뭔가를 바인딩할 필요가 있을때는 좋겠죠
    • 워드 선언에서 [let을 바로 이용할수도 있어요
      • : foo ( a b -- n )
        [let | b [ ]
                a [ ] |
              a b * ] ;
        • 스택에서 꺼내는 순서때문에 b부터 바인드함을 주목하세요
        • 귀찮죠?
      • :: foo ( a b -- n ) a b * ;
        • 이렇게 :워드가 아니라 ::워드를 사용하면 편리
        • M:, MEMO:, MACRO:에 대한 M::, MEMO::, MACRO::도 있음.
          • M:은 메서드 선언시 사용
          • MEMO:은 memoization을 이용할때 사용
          • MACRO:은 (리습같은)매크로 선언시 사용
    • 다른 언어에서의 '변수'처럼 값을 바꾸기
      • n!의 형식으로 바인딩을 만들때 바인딩하고
      • 변수의 값을 취할때는 n으로 사용하고
      • 변수에 값을 넣을때는 42 n!처럼 하고
      • 예를 들어서
        • [let | n! [ 0 ] |
               42 n!
               n . ]
          • 처음엔 n의 값은 0이었지만
          • 42 n!을 통해서 42로 세트
    • 이렇게 바인딩에 나타낸 값은 sequence나 quotation같은 literal식에 그대로 적용할수있음
      • [let | a [ 3 ] b [ 4 ] | { a b } ] .
      • 시퀀스나 quotation등을 만들때 편리하겠죠
      • 또한 fried-quotation등에 적용할때도 바로 적용이 가능해서 함수의 조합등에도 편리
  • dynamic scope와 전역변수
    • USE: namespaces
    • 일반적으로 dynamic scope한 변수를 만들려면
      • SYMBOL:등으로 사용할 변수이름을 등록하고
      • 42 the-answer set
        • 이렇게 변수에 값을 대입
      • the-answer get .
        • 이렇게 값을 얻고
    • 좀 더 편리한 몇가지를 제공하는데요
      • 정수 증가/감소
        • inc
        • dec
        • 1씩 증감하겠죠. i++, i--처럼
      • 불리언 토글
        • on
        • off
        • 심플하죠?
      • 혹은 변환
    • 전역변수
      • 전역변수는 set, get대신에

        • set-global
        • get-global

        그리고 전역변수로 선언을 하더라도 get, set으로 dynamic scope에 뭔가를 지정하면 나중에 지정한것을 지칭함

        결론적으로 전역변수는 namestack의 맨 아래쪽에 위치한다는

        다른 값으로 스코프 동안 잠깐 대체했다가 다시 원래의 상태로 돌아오도록

        예를 들어, input-stream, output-stream와 같은 전역변수를 원하는 스코프에서 잠깐 다른 스트림으로 대체하여 표준입출력을 다른 출력으로 바꾼다거나 하는게 가능하겠죠

        팩터에서 dynamic-scope와 전역변수는 사실 namestack으로 구성하고 각 스코프는 하나의 namestack이라고 설명할수있습니다

    • 일반적인 dynamic-scope의 예
      • with-input-stream, with-output-stream
        • input-stream, output-stream을 주어진 quotation을 실행하는 동안 대체해서 일반적인 print, pprint나 read등의 표준입출력 워드를 이용해서 원하는 스트림으로 재지향

      • with-string-reader, with-string-writer
        • [ { 1 2 3 } . ] with-string-writer .
        • 저렇게 하면 표준출력을 문자열로 '캡쳐'할수있겠죠?
  • "일반적인" 루핑
    • while, until, loop와 같은 일반적인 제어구조를 quotation을 통해서 표현하기
    • loop ( quot -- )
      • quot의 타입은 ( -- ? )
      • quotation이 f을 되돌릴때까지 반복실행
    • while ( pred body tail -- )
      • pred ( -- ? )
        • 이 quotation이 f을 되돌릴때까지
      • body ( -- )
        • 이 quotation을 반복
      • tail ( -- )
        • 그리고 루프가 끝날때 이 quotation을 한번 실행
    • 그리고 until ( pred body tail -- )
      • while와 같지만
      • pred가 t일때까지 반복
  • 재귀
    • 재귀에 관해서는 별로 쓸말이 없는것 같은데 ^^;
    • :: factorial ( n -- n! )
       n 1 <=
       [ 1 ]
       [ * n n 1- factorial ]
      ;
      • 이런 간단한 예제정도이지 않을까 싶어요
    • 덧붙이자면, tail-call optimization을 해준다고 하네요 :-)
    • 그리고 재귀로 표현이 가능한것들은 iteration(each, map...)등으로 대부분 표현이 가능하지 않을까요?
  • 심볼, 상수
    • 변수에 이름을 주거나 할때 사용하는 이름도 사실 '워드'이기 때문에 보통은 다음은 에러
      • 42 the-answer set
        • the-answer라는 이름으로 변수를 만들고 이에 값을 42로 세팅
        • 사실은 'the-answer'라는 워드가 정의되어 있지 않기 때문에 word not found error겠죠
      • 42 \ the-answer set
        • 이렇게 \ word라는 식으로 word 자체를 스택에 값으로 쌓아서 전달해야하죠
        • 조금 불편하죠?
      • 그래서 이렇게 "자기 자신으로 평가되는 심볼"이 필요하죠
        • 리습이나 루비에서는 일반적이죠?
          • 심볼
          • 키워드
      • SYMBOL: the-answer
        • 이렇게 선언하면 the-answer을 그 자체로 스택에 쌓는 '심볼'을 선언해요
        • 구현내용을 보면
          • SYMBOL:, SYMBOLS:은 define-symbol을 내부적으로 사용하는 parsing word구요
        • define-symbol워드는 단순히 주어진 이름에 대해 define-constant해서 그 자체를 상수로서 만들어줘요
        • 결국 그 심볼 그 자체로 평가되는 상수를 선언하는거죠
      • 결국 SYMBOL: the-answer을 통해 다음처럼 쉽게 가는게 가능해지죠
        • 42 the-answer set
        • the-answer get .
    • 그리고 팩터에서 어떤 상수에 이름을 주기는 어떻게 하냐면요
      • 상식적으로 생각해보면 그냥 워드를 선언하듯이 하면 되겠죠
        • : the-ultimate-answer ( -- n ) 42 ;
      • 그런데 이를 위한 방법이 또 있어요
        • CONSTANT: the-ultimate-answer 42
        • 파싱워드고 내부구현은 사실 define-constant 워드를 이용해요
  • 박스
    • '박스'은 '참조'로서 사용이 가능해요
    • 어떤 다른값이 바뀌길 원하거나할때 사용할수있게죠
    • USE: boxes
    • <box>
      • 이렇게 생성해서
    • dup 42 swap >box
      • 이렇게 박스에 값을 넣어요
    • box>
      • 이렇게 값을 꺼내고요
    • 보통의 accessor 문법이랑 같죠?
    • 그리고 박스가 어떤값을 담는지를 판별
      • box-empty?
      • box-full?
  • 사족
    • 일반적으로 사용하면 편한 테크닉들인데요
    • 가능하면 더 표현이 간결하고
    • 더 명확한 표현법이 있다면
    • 전역변수나 while와 같은 루핑이나
    • mutable한 변수의 사용은 피하는게 좋지 않을까요?
    • 그밖에 control flow cookbook의 내용들을 잘 숙지하는것도 더 좋은 방법을 찾기 좋다고 생각함
신고
posted by 아겔-_- 2009.02.19 21:52
함수형언어를 사용하면 빈번하게 curry, compose와 같은 함수연산을 적용합니다. 하스켈과 같은 언어에서는 단순히 (1+)나 f . g와 같은 언어적인 지원을 통해 편리하게 이용이 가능한데 팩터는 그런 문법적인 지원이 없습니다. ㅜ.ㅜ 그래서 부득이하게 다음처럼 curry하거나 했습니다.
( scratchpad ) 1 [ + ] curry
...
( scratchpad ) 2 swap call .
3
그리고 함수조합은 다음처럼 했습니다.
( scratchpad ) [ sq ] [ 1+ ] compose
...
( scratchpad ) 3 swap call .
10
아... 뭔가 느낌이 안오죠? 그래서 "fry" vocab을 사용해서 다음처럼 깔끔하게 표현이 가능해졌어요.
! curry연산은...
( scratchpad ) USE: fry
( scratchpad ) 1 '[ _ + ]
[ 1 + ]
( scratchpad ) 2 swap call .
3

! compose연산은...
( scratchpad ) [ sq ] [ 1+ ] '[ @ @ ] 3 swap call .
10
단순히 [ ... ]이 아니라 '[ ... ]으로 quotation을 묶고, 그안에 _, @을 이용하여 리터럴이나 다른 quotation을 배치하는 간단한 fry vocab인데, curry, compose을 더 자연스럽게 표현할수있습니다. :-)
신고
posted by 아겔-_- 2009.02.17 22:20
저의 개인 factor clone에 io.encodings.korean을 push했습니다.

사실 지난 주말부터 factor offical git-repository에 올라와있어서 원하는 사람은(특히 개별적으로 팩터를 빌드하시거나 하시는 분들) 얼마든지 한글코드 지원을 맛보실 수 있었습니다.

Daniel Ehrnberg의 큰 갈굼도움으로 좋은일을 할수있었던것 같습니다. (Daniel, thank you!)

도움말 문서도 얼추 작성했고 보람차네요.

현재로서는 cp949(euckr, uhc, 확장완성형)만을 지원하지만 조합형이나, 쌩뚱맞게 euc-jp코드에 대한 작업도 해나갈 생각입니다. (마지막것두 io.encodings.korean에 넣어볼까요?^^;)

나름 별거 아닌 인코딩 지원이지만, 이를 위해서 많은 지원을 해준 Slava Pestov에게도 고맙네요. (알고보니 저보다 두살이나 어리더군요! 아... 참 인생 헛살았다는 느낌;;)


팩터가 io.encodings.korean와 연관하여 개선된 부분과 개선될 부분도 생겨서 기쁩니다.
  • 리소스 pathname에 vocab:을 지정가능하게되었습니다. 예를 들어, resource:work/io/encodings/korean/cp949.txt
  • 와 같이 work디렉토리나 basis디렉토리에 참조가 있을수밖에 없었는데, 이를 vocab:io/encodings/korean/cp949.txt와 같이 어떤 위치에 있건 vocab의 위치에 따라가게. (현재 git버젼엔 반영)
  • cp949, shift-jis, euc-jp등 unicode.org에서 제공하는 코드 테이블을 이용하여 매핑하는 방식을 공식적으로 지원하기 위한 파서/코드테이블 vocab (작업중)



마지막으로 스샷 하나 올립니다. 아직 ui-listener에서는 유니코드 한글출력이 구현되지않아 어렵지만, 유니코드를 정상적으로 지원하게 설정한 emacs+fuel에서는 한글을 느끼실수있답니다. ^^
신고

'삽질+돈되는짓 > FactorLanguage' 카테고리의 다른 글

Imperative Factor  (0) 2009.02.21
어째서 함수의 조합은 복잡해야만 할까?  (0) 2009.02.19
io.encodings.korean 커밋  (2) 2009.02.17
Factor에서 개발하기  (0) 2009.02.15
Factor History & Features  (0) 2009.02.14
concatenative language?  (1) 2009.02.14
posted by 아겔-_- 2009.02.15 15:34
Factor에서 개발하기

Factor에서 개발하기

  • 작성
    • 아겔 <ageldama@gmail.com>
    • 2009년 2월 15일 일요일
  • 개발패턴
    • 1.A. factor ui-listener에서 tools.scaffold을 이용해서 vocab을 먼저 만들거나 (신규 vocab을 만들때)
    • 2.A. 기존의 소스를 검색한다.
      • ui리스너에서 Contro-e (sources)등으로 소스를 검색해서 파일을 열어 보기/수정
    • 3. 편집기에서 소스를 수정
    • 4. reload을 통해서 수정한 vocab reload
      • fuel이라면 C-c r
      • 혹은 "my-vocab" reload
      • 다 귀찮으면 refresh-all (변경한 소스만 자동으로 다시 로드)
    • 5. 테스트
      • "vocab-name" test
        • 단위테스트를 미리 작성해놓고 단위테스트를 통해서 테스트하거나
      • 손으로; 인터랙티브하게;
  • 지원하는 편집기
    • vim
    • gvim
    • emacs
    • scite
    • textmate
    • editplus
    • notepad++
    • jedit
    • 은근 많네;
    • editors vocab의 available-editors을 때려보삼
  • FUEL
    • emacs + factor
    • 별도로 factor-ui을 거치지 않고 커먼리습+slime+emacs와 같이 개발가능
    • 거의 대부분 ui리스너의 기능을 쓸 수 있지만, 그래도 ui리스너보다는 덜 강력
    • 그래도 이맥스에서 키보드만으로 작업하는게 좋을때
      • ui리스너도 키보드만 갖고 되긴하지만
    • 자세한건 "FUEL설정"문서를 봐주삼
  • VIM연동
    • 다른 편집기도 거의 비슷해서 생략하고 이거만 설명
    • 일단 vim을 쓸건지 gvim을 쓸건지 결정
    • vim/gvim으로 문법하일라이팅이랑 ui리스너에서 :edit등을 이용해 소스를 바로 편집기에서 확인/편집하는 정도의 기능
    • 그리고 vim/gvim의 경로를 PATH환경변수에 등록
      • 팩터에서 vim-path을 설정하는 방법이 있는데 그게 더 귀찮;
    • vim/gvim의 vimfiles에 factor/misc/vim이하의 문법파일등을 복사해주기
      • 문법강조등을 하려면 필요해요
    • 그리고 USE: editors.gvim 해서 편집기 연동 vocab을 로딩
      • 로딩한 다음에 나중 팩터 세션에도 적용하려면 save로 이미지를 저장해야겠죠?
  • tools.scaffold 이용하기
    • vocabulary은 word의 집합
      • 팩터에서 프로그램 단위
      • 다른 언어에서의 '모듈'이랑 비슷한 개념
      • 그리고 하나의 vocab은 하나의 프로그램일수있고
        • MAIN: 선언을 갖는 vocab은 애플리케이션
        • 애플리케이션은 실행도 되고, standalone으로 배포도 가능
        • 자세한 내용은 이후의 애플리케이션, 배포 섹션을 참고바람
    • 보통 vocab은 팩터이하에서 일정한 디렉토리/파일 레이아웃을 갖는데
    • 일일이 boiler-template하기 귀찮으니까 사용
    • 팩터에서는 뭔가 작은 모듈을 만들거나 프로그램을 모두 vocab으로 나누어서 작업하니까
    • 일단 USE: tools.scaffold
      • 그리고 이후에 tools.scaffold을 이용해 생성할 소스에 새길 개발자 이름을 설정해주자
      • "I'm your father" developer-name set-global
        • set-global이 namespaces에 있는 전역변수를 설정하는 word기 땀시 namespaces가 로드되있으면 좋겠져
        • developer-name은 전역변수이름
        • I'm your father부분만 이름으로 바꿔주세용
        • 그리고 일단 세팅했으면 이것도 저장해서 나중 세션에도 적용하려면 save로 이미지 저장
    • 그럼 새로운 vocab을 만들어봐요
      • "resource:work" "my-hello" scaffold-vocab
        • "resource:work"부분은 팩터의 리소스 시스템 표기법
          • 어쨌든 work 리소스 아래에 새로운 vocab을 만들겠다는 선언
          • 리소스 시스템에 대한 자세한 설명은 이후 '리소스'부분을 참고바람
          • 일단은 factor 디렉토리 아래의 core, basis, extra, work을 지정하는 상대적인 경로지정법이라고만 생각해두면 편함
        • "my-hello"은 새로운 vocab의 이름
          • 주) factor/extra/hello-world가 이미 있어서 이런 어정쩡한 이름을;;;
          • factor가 설치된 디렉토리 이하의 work/my-hello 디렉토리에 파일들이 생겼음을 알 수 있음
          • 디렉토리의 개별 파일에 대한 설명은 일단 중요한 .factor 파일들만
            • 자세한 설명은 소스 레이아웃 부분을 참고바람
            • my-hello.factor
              • 해당 vocab의 소스파일
            • my-hello-tests.factor
              • vocab의 단위테스트 스크립트파일
            • my-hello-docs.factor
              • vocab의 문서화 파일
            • 그 이외에 *.txt파일들이 있기도 하고, docs파일은 기본적으로 생기지 않기도 하는데 이에 대한 설명은 이후에 자세히.
    • 이제 코딩!
      • vocab.factor에 선언들을 작성하고
      • vocab-tests.factor에 단위테스트를 작성하고
      • 테스트 하면서 개발 사이클을 돌리면 되삼!
  • 리소스시스템
    • 팩터 배포판에 포함된 서브디렉토리를 추가적인 경로로 이용할 수 있음
    • 자바의 클래스패스등과 유사하게
      • 차이는 자바의 그것은 다수의 경로를 줄수있고
      • 자바의 경우는 클래스로더를 이용해야 하지만
      • 팩터는 일반적인 파일시스템 인터페이스에 연동되어 있음
    • 간단히 이해하자면
      • "." resource-path .
        • 이렇게 해보면 resource-path을 얻어볼수있음
        • 당연히 factor가 설치된 디렉토리임
      • "resource:work/foo/foo.factor"
        • 이렇게 하면 팩터 디렉토리 이하의 work/foo/foo.factor 파일을 지정하는 pathname임
        • 일반적인 파일연산에 바로 적용이 가능한 형태
      • "resource:work/foo/foo,factor" ascii file-contents .
        • 팩터 디렉토리이하에서 work/foo/foo.factor파일을 ascii인코딩으로 읽어서 문자열로
        • file-contents, file-lines등과
        • ascii, binary, utf8, cp949등 다양한 인코딩을 지정가능
    • 이후 vocabs.loader등 vocab 로딩 시스템과 연동되어 매우 편리
    • PLT Scheme등에서의 끔찍한 모듈 배치 방식을 생각하면 심플하고 유연한 시스템
  • 소스 레이아웃
    • 팩터 시스템의 각 디렉토리 및 파일에 대한 설명
      • core/ 및 basis/ 디렉토리
        • 팩터 기본시스템의 소스들
        • vm에 내장한 primitive제외한 팩터의 기초 라이브러리 및 컴파일러, 파서까지
        • bootstrap단계에서 각각 stage1, stage2에 이들을 로딩해서 이미지를 만들어 팩터시스템을 구성
      • fonts/ 디렉토리
        • 팩터 UI리스너에서 사용하는 ttf파일들
      • misc/ 디렉토리
        • 기타 아이콘이나
        • emacs fuel이나
        • 편집기 문법파일과 같은 잡다한 파일들
      • extra/ 디렉토리
        • 팩터 공식배포판에 함께 배포하는 추가적인 라이브러리, 프로그램들
        • core나 basis보다는 추가적인것들이 여기에
          • 예) 테트리스, curses 바인딩, peg 등등
      • work/ 디렉토리
        • 사용자가 작성하는 vocab, 프로그램의 내용들이 여기에
        • git을 통해 팩터에 contribution하더라도 여기에 있는 내용은 push되지 않으므로 주의
        • 이 디렉토리만이 read-write라고 생각하고 작업하는게 적절
      • factor.exe, factor.exe, factor VM 실행화일
        • factor.dll 같은것도 있고
        • 어쨌든 factor 시스템을 구성하는 기본 vm
        • factor.com, factor.exe은 윈도에서 서로 콘솔기반, 윈도애플리케이션 이렇게 구분
        • OSX, 기타 유닉스 시스템에서도 factor 실행화일로
      • *.image
        • factor.image가 기본 이미지
        • 부트스트랩을 위한 기초 이미지도 이렇게
        • 기타 사용자가 만든 이미지도 여기에 이렇게 저장
        • 각 플랫폼/아키텍쳐별로 이미지는 네이티브 코드가 포함되어있으므로 서로 호환되지 않으므로 주의
    • 어떤 vocab에 있어서 소스파일 및 기타 데이터의 배치
      • 소스코드는
        • foo.bar vocab을 기준으로 설명
        • foo/bar/bar.factor
          • vocab의 소스코드
        • foo/bar/bar-docs.factor
          • vocab의 documentation
          • help system을 통해서 확인하는 문서등
          • 자세한 내용은 문서화 섹션을 참고
        • foo/bar/bar-tests.factor
          • 해당 vocab에 대한 단위 테스트들을 담은 파일
          • "foo.bar" test을 통해서 단위테스트 실행
          • 자세한 내용은 단위테스팅 섹션을 참고
      • 기타 정보는
        • tools.vocabs vocab을 보셈
          • vocab의 내용을 보면 다양한 word들
          • all-vocabs 같은 유용한것들도
        • summary.txt
          • 해당 vocab의 간단한 설명
          • vocab-summary, set-vocab-summary을 통해서
        • tags.txt
          • 해당 vocab의 범주에 속하는 태그들을 스페이스로 구분해서 적어줌
          • 예를 들어 "foo.bar" vocab-tags . 이렇게 foo.bar vocab의 태그들을 나열
          • set-vocab-tags, add-vocab-tags로 태그를 추가
        • authors.txt
          • vocab의 작성자를 한줄씩 적어주는 파일
      • 데이터 파일들은
        • 모듈이 위치한 디렉토리에 있으면 리소스 시스템을 통해서 로딩가능
        • 예를 들어, 필요한 코드테이블이나 뭐 그런것들
  • 컴파일, 로드, 이미지
    • 컴파일? 로딩?
      • USE: foo와 같이 하나의 vocab을 컴파일/로드
      • USING: kernel math ;
        • 이렇게 다수의 vocab을 한번에 로딩
      • 내부적으로 vocabs의 load-vocabs을 이용하여 구현하였음
    • qualified path
      • USE: math하면 그에 선언된 + 워드를 바로 사용이 가능함
        • 이름공간에 바로 import하는 방식
      • QUALIFIED: math
        • 모듈의 이름을 prefix로 사용하려면
        • 그리고 사용시에는 math:+
      • QUALIFIED-WITH: math m
        • math모듈을 m을 prefix로 하여 import
        • m:+ 이렇게 참조함
    • vocab의 이름은 어떻게 구성되나?
      • "foo" vocab은
        • resource:core/foo/foo.factor가 소스이건 쉽게 이해되죠?
      • "foo.bar" vocab이
        • resource:work/foo/bar/bar.factor 이렇게
        • 꼭 같은 위치에 모든 vocab path가 함께 있을 필요가 없음
          • foo은 core에 있고
          • foo.bar은 work에 있고
          • 그래도 둘 다 같은 vocab에 있는것처럼 seamless하게 이용
        • 맨 마지막 경로의 이름 (foo.bar면 bar)가 소스이름이 되는거죠
    • 로드가능한 vocab은 모두 vocab-roots 전역변수에 있는 디렉토리 이하에 위치
      • vocabs.loader을 살펴보기
      • 팩터 이하의 디렉토리가 아니라 외부의 소스를 로드하려면 add-vocab-root 워드를 이용하여 추가
      • resource:work에 있건 resource:core에 있건 관계 없이 그 vocab의 이름만으로 로드가능
    • reload, refresh
      • 소스를 작업하면서 변경하면 다시 불러들여야 하는데 이럴때 적용
      • foo.bar모듈을 예로 들어 설명하면
      • "foo.bar" reload
        • 특정 vocab의 소스와 문서를 다시 읽어들이기
      • "foo.bar" refresh
        • 해당 경로prefix의 모든 소스와 문서를 다시 읽어들이기
        • 그 이하에 딸린 vocab도 모두 불러옴
      • refresh-all
        • 현재 로드한 모든 vocab에 대해서 파일변경을 검사해서 모두 로드
        • 변경한 파일만 다시 로드하기 때문에 생각보다 느리지 않음
    • 이미지
      • 팩터엔 스몰톡, 커먼리습과 같은 이미지기반 개발을 위한 이미지 시스템이 갖춰져있음
      • 매번 팩터를 시작할때마다 로딩하기 부담스러운것들이 많으니까
        • 컴파일도 다시해야하니까
        • 한번 컴파일/로드한 다음에 이미지로 저장해뒀다가 다시 불러들여서 세션을 복원
        • 팩터시스템의 설정값이나 개발한 프로그램의 설정을 그대로 복원하기도 편리
      • 팩터 시작시에 이미지를 지정
        • factor -i=IMAGE-FILENAME
        • 뭐 이렇게 이미지 파일을 지정할수있음
        • 이미지 파일이름을 지정하지 않으면 기본적으로 factor.image 파일을 로딩
      • 이미지를 저장하기
        • save을 이용해서 현재 세션의 이미지를 변경해서 저장
        • "foo.image" save-image 이렇게 다른 이미지 파일이름으로 저장
      • 처음 팩터를 컴파일하고 조성할때 bootstrap할때는 bootstrap-image을 이용해서 각 stage별로 컴파일/로드
      • 커먼리습이나 스몰톡처럼 standalone으로 배포할 프로그램을 만들때도 사실 팩터vm와 해당 애플리케이션을 위해 stripped한 이미지를 함께 배포
        • 애플리케이션 개발과 배포에 대해서는 이후의 장에서 설명
        • 배포작업도 자동화되어있음
        • 배포작업을 위해서 별도의 작업이 거의 불필요하고 커먼리습구현들처럼 어마어마하게 큰 이미지를 만들지도 않음
          • 주) CLISP에서 "hello, world" standalone이미지가 27메가라는 놀라운 포스팅도 있었죠
  • 애플리케이션, 배포
    • vocab은 라이브러리/모듈이기도 하지만, 하나의 프로그램이기도함
    • 기존에 있는 애플리케이션을 실행하기
      • run ( vocab-spec -- ) 으로 애플리케이션을 실행
      • 애플리케이션은 vocab의 이름으로 지정이 가능
      • 예를 들어 "tetris" run으로 resource:extra/tetris을 애플리케이션으로 실행
      • 이렇게 애플리케이션인 vocab이 은근히 많아요. 찾아서 실행해보는것도 은근 재밌^^;
    • 새로운 애플리케이션을 만들기
      • MAIN:을 이용해서 vocab을 애플리케이션으로 만들수있음
      • MAIN: main-word
        • main-word을 애플리케이션의 시작점이 될 word로 지정
        • 당연히 입력이 없고 출력만 있는 word을 지정해야겠죠?
    • 애플리케이션을 배포하기
      • 애플리케이션을 standalone executable과 최적화한 이미지로 만들어서 실행화일만 실행하면 바로 애플리케이션이 뜨도록 배포가능
      • 예를 들어, "tetris" 애플리케이션을 배포하려면
        • "tetris" deploy을 통해서 팩터 디렉토리 이하에 Tetris디렉토리에 standalone application으로 묶어서 만들어줌
        • 컴파일해서 소스 정리하고 이미지 사이즈 최적화하고, native optimization을 하느라 좀 오래 걸림
        • 또는 추가적으로 옵션을 줘서 standalone application을 만들기 위해서 "tetris" deploy-ui을 통해서 대화상자에서 옵션주고 만들수도
        • deploy시 설정할 옵션을 저장하고 싶으면 deployment configuration을 포함해서 vocab에 설정으로 포함가능
  • 단위테스트
    • 단위테스트?
      • 팩터에서 단위테스트 프레임웍을 이용하여 단위테스트 적용하기
      • tools.test
      • 단순히 단위테스트 파일의 내용을 하나씩 실행하는 스크립트 형식
        • 펄의 .t파일이라 비슷하게
    • 단위테스트 작성하기
      • foo vocab이라면
      • 테스트스크립트는
        • 같은 디렉토리의 foo/foo-tests.factor파일이거나
        • foo/tests/ 디렉토리에 모든 *.factor 파일이 테스트스크립트로 적용가능
      • 테스트 항목은
        • unit-test
          • 두개의 quotation을 인자로 하는데 두 quotation의 스택 결과가 같으면 테스트를 통과
          • 그렇지 않을때 테스트 실패
          • [ 6 ] [ 2 3 + ] unit-test
            • 뭐 이런식으로
        • must-fail
          • 예외를 던지면 테스트 성공
          • [ throw-some-error ] must-fail
        • must-fail-with
          • must-fail와 같으나 특정한 조건에 부합하는 예외만 성공
        • 그 이외에 스택효과에 대한
          • must-infer
          • must-infer-as
    • 단위테스트 실행하기
      • "foo.bar" test로 foo.bar vocab에 속한 모든 vocab의 테스트를 수행
      • test-all로 모든 vocab의 테스틀 수행
        • 왠만하면 하지마셈;;;
  • 문서화
    • 주) 작성하다가 저도 공부해야 하는 부분이고, 귀찮아서 일단 안쓰기로;;;
    • 주) 나중에 아예 다른 문서로 정리해야할 주제일듯
신고

'삽질+돈되는짓 > FactorLanguage' 카테고리의 다른 글

어째서 함수의 조합은 복잡해야만 할까?  (0) 2009.02.19
io.encodings.korean 커밋  (2) 2009.02.17
Factor에서 개발하기  (0) 2009.02.15
Factor History & Features  (0) 2009.02.14
concatenative language?  (1) 2009.02.14
FAQ/Vocabulary  (0) 2009.02.13