2016년 12월 22일 목요일

클로저로 단순한 GUI 프로그램을 만들어보았다.

아주아주 단순한 클로저 프로그래밍을 해보았다. 이전에 웹으로 연결도 해보고 클로저스크립트도 한번 경험해보았지만 아직도 클로저 라는 언어에 확신이 없다. (왜냐하면 내가 제대로 모르기 때문...ㅠㅜ)
그래서 하나를 짬내서 만들어 보았다. 처음에는 swing을 썼다. 참으로 고통이었다. seesaw라는 라이브러리가 있는 걸 확인하고 seesaw를 살짝 사용했다.
저녁에 짬내서 만들면서 느낀 점은 참으로 힘들었다는 점이다.
나의 능력이 문제인지, 내 뇌가 아직 클로저라는 리스프계열에 적응을 못하고 있는 것인지 잘 모르겠다.
막연히 Swing을 쓰면 되겠지라고 생각했었는데... 정말 자바로 그냥 짰으면 순식간에 만들었을 것이라는 생각이 들었다.
아직 내가 클로저를 짬내서 3개월 정도 해봤는데 어렵다는 것은 내가 아직 클로저가 가지는 개념을 모르고 있다는 생각이 든다.

하지만 확실한 것은 리스프 프로그래밍은 정말 어렵다. 처음으로 하는 GUI를 다루는 것이라 버튼 하나 넣는 것에도 애를 먹었다. 내가 고작 만든 것은 이메일만 필터링해서 나열하는 것이다.
대량메일을 보내기 위해서!
그래서 만약
AAA@AAA
BBB@BBB.com
CCC@CCC.net
뭐 이런게 있으면
BBB@BBB.com, CCC@CCC.net
뭐 이렇게 만들어 주는 것이다. 정말 별거 아닌 것을 만들었다. REPL에서 그냥 치면 바로 나오는 걸 만든 것이다.


그런데 참으로 느낀 점은...
재미있었다.
내 앞에 있는 무언가 보이지 않는 큰 힘이 꿈틀거리는데 잡을 수 없는... 그런 느낌?
잡으려고 마구 휘저었지만
잡지 못했고 별거아닌 노력의 산물만 남았지만
정말 재미있었다.
뭔가 쌓아올리는 느낌?

어쨋든 github로 관리하면서 더 손봐야겠다. (과연 할런지...)
https://github.com/ssisksl77/sman

2016년 12월 21일 수요일

[jvm]04 - Instruction Set Summary

Instruction Set Summary

JVM명령은 1바이트 연산코드(opcode)로 구성되어있다.뒤에 딸려오는 제로(zero) 또는 다른 피연산자(operands)는 연산에 쓰인다.많은 명령어들은 피연산자가 없고 그냥 연산코드만 가지고 있다.
예외는 무시하고, JVM인터프리터의 내부 loop는
이렇게 생겼다고 한다. 피연산자의 수와 사이즈는 연산코드에 의해 결정된다. 만약 피연산자의 사이즈가 1바이트보다 크다면?

그것들은 빅엔디안(big-endian order : 데이터의 최상위 비트가 가장 높은 주소에 저장되므로 그냥 보기에는 역으로 보인다.)방식으로 저장된다.

예를들어, 로컬변수 unsigned 16비트 인덱스는 두개의 unsigned 바이트로 저장된다.(byte1 과 byte2).
값은

 이다.


Types and the Java Virtual Machine

JVM 명령어 셋의 대부분은 명령의 타입정보를 인코드한다.
예를들어 iload명령은 로컬 변수(int값이어야만 한다)의 내용을 피연산자 스택에 로딩한다.
floadiload와 똑같이 행동한다.(물론 float값을 사용한다.)
두 명령은 똑같은 구현을 가지고 있지만 서로 다른 연산부호(opcode)다.
  • i : int operation
  • l for long
  • c for char
  • f for float
  • d for double
  • a for reference
어떤 것들은 타입문자(type letter)가 없다. 예를들어 arraylength는 항상 object를 실행하지만 배열이다. goto를 보자. 무조건적인 제어 전환(control transfer), 타입이 있는 피연산자를 실행하지 않는다.

[jvm]03 Special Method

1. Special Method

자바로 만들어진 모든 생성자는 instance initialization method로 나타내어진다. (그놈의 이름은 ) 이 이름은 컴파일러에서 볼 수 있다. (왜 컴파일러에서?) 왜냐하면 은 유효한 식별자(identifier)가 아니기 때문이다. 이것은 자바 언어로 바로 씌여질 수 없다. 인스턴스 초기화 메소드(Instance initialization methods)는 오로지 JVM안에서 invokespecial명령어로 호출된다. 그리고 이것들은 오로지 초기화안된 클래스 인스턴스에서 호출될 것이다. 인스턴스 초기화 메소드(instance initialization method)는 생성자의 엑세스 권한을 가진다.

클래스 또는 인터페이스는 최소한 한나의 초기화 메소드가 있다. 그리고 그 메소드를 호출해서 초기화가 진행된다. 그 초기화 메소드는 아규먼트가 없으며 void이다. 이라는 특별한 이름을 가진다. class 파일의 version number 가 51이상이면, 추가로 ACC_STATIC 세팅값이 있어야 한다. 은 컴파일러에서 제공한다. 이유는 은 유효한 식별자(identifier)가 아니기 때문(init과 마찬가지) Class and interface initialization methods는 JVM에 의해 내부적으로 호출되어진다. 이것들(methods)은 어떤 JVM명령어로도 직접적으로 호출될 수 없다. 하지만 간접적으로는 호출될 수 있다.(class initialization process에서)

2. Exception

JVM에서 예외(exception) 단순히 Throwable, 아님 Throwable의 subclass의 클래스 인스턴스이다. 예외를 던지는 것은 예외가 던져진 곳(point)에서 즉각적 로컬 외(nonlocal) 컨트롤의 이전이 된다. 대부분의 예외는 동기적으로 일어난다. 비동기적인 예외 또한 프로그램 실쟁 중에 일어날 수도 있다.

2016년 12월 15일 목요일

[jvm]02 Run-Time Data Areas

JVM은 다양한 런타임 데이타 지역을 정의한다. 그리고 이것들은 프로그램 실행중이 사용된다. 몇몇 data area는 JVM이 시작할 때 만들어지고 JVM이 꺼질 때 파괴된다. 다른 data area는 thread 별로 있다. thread별 data area는 thread가 시작되고 죽을 때 그 삶을 같이 한다.

1. pc register

JVM은 다수의 스레드의 동시(at once) 실행을 지원한다. JVM의 스레드 각각은 자기 고유의 pc (program counter) register를 가진다. 어떤 시점에서든, 각각의 JVM스레드는 하나의 메소드 코드를 실행하고 있을 것이다. 즉 해당 스레드의 현재 메소드(current method)를 말이다. 만약 method가 native(native의 뜻은 뭐지? -> native method를 말하는 듯)하지 않다면, pc register는 현재 실행되고 있는 JVM명령어의 주소를 포함한다. 만약 메소드가 현재 스레드에 의해 실행되고 있는게 native라면, JVM의 pc register의 값은 undefined다. JVM의 pc register는 returnAddress 또는 native pointer(on specific platform)를 담기에 충분하다.

2. Java Virtual Machine Stacks

JVM Thread는 각각 private JVM stack을 가진다.(thread가 생성될 때 같이 만들어진다.) JVM stack은 frame을 저장한다.(frame은 나중에 나온다.) JVM stack은 C언어에서 만든거랑 유사하다. JVM stack은 push, pop frames를 제외하고 절대로 직접적으로 수정되지 않는다. frames는 힙에 할당되어진다. JVM stack을 위한 memory는 인접해 있을 필요없다.

3. heap

JVM은 JVM Thread가 공유하는 heap이라는 공간을 가지고 있다. heap은 모든 클래스 인스턴스와 배열이 할당되는 런타입 데이터 공간(run-time data area)이다. heap은 JVM이 시작될 때 만들어진다. 오브젝트를 위한 힙 저장소는 storage managerment system(가비지컬렉션)에 의해 되돌려 받는다. heap은 고정된 사이즈 또는 확장되도록 할 수도 있다.

4. Method Area

JVM이 공유하는 method area는 class의 구조 (such as the run-time constant pool, field and method data, and the code for methods and constructors, including the special methods used in class and instance initialization and interface initialization.)를 담는다. method area는 JVM이 시작할 때 만들어진다. 비록 논리적으로 heap의 부분이다.

5. Run-Time Constant Pool

class파일 안에 per-class, per-interface의 런타임 constant_pool테이블을 보여주는 곳. (constant,ranging from numeric literals known at compile-time to method and field references that must be resolved at run-time이 들어있음) The run-time constant pool은 일반적인 프로그래밍 언어에 심볼테이블(symbol table)과 유사한 것이라 생각하면 된다. 물론 이건 그것보다 더 많은 범위를 가지고 있다. 각각 run-time constant pool은 JVM의 method area에 할당되어 있다. class나 interface의 run-time constant는 걔네들이 만들어질때 JVM이 구성해준다.

5. Native Method Stacks

JVM은 일반적인 stack을 이용한다. 구어체로 "C tacks"라 부른다. 왜 stack을 사용하냐면 네이티브 메소드(native methods)를 지원하기 위해서다.(자바가 아닌 언어로 씌여진 메소드) 네이티브 메소드 스택은 JVM 명령어 모음의 인터프리터 구현(C언어로)으로 사용된다.

6. frames

프레임(frame)은 데이터와 부분 결과를 저장하려고 사용한다. 뿐만 아니라 dynamic linking, return values for methods, and dispatch exceptions. 이럴 때 사용된다. 새로운 프레임은 메소드가 호출될 때마다 각각 만들어진다. 그리고 메소드 호출이 완료되면 죽는다.(그것이 성공이건 익셉션이건...) 프레임은 각자 로컬변수 배열이 있고, 피연산자 스택 그리고 현재 메소드의 클래스의 런타임 constant pool의 참조.. 가 있다.

7. Local Variables

frame은 각각 local variables 배열을 가짐. 길이는 컴파일 타임에 결정 single local variable은 boolean, byte, char, short, int, float, reference, or returnAddress. A pair of local variables은 long or double. 타입을 가진다.

8. Operand Stacks

각각 frame은 last-in-first-out(LIFO)stack 을 가진다(known as its operand stack). 한가지 알아야 할 점은 double, long은 스택이 두개가 하나다. 그래서 스택에 쌓일 때 두개씩 쌓인다.

[jvm]01 Type and Values

1. Integral Types and Values The values

The values of the integral types of the Java Virtual Machine are:

  • For byte, from -128 to 127 (-27 to 27 - 1), inclusive
  • For short, from -32768 to 32767 (-215 to 215 - 1), inclusive
  • For int, from -2147483648 to 2147483647 (-231 to 231 - 1), inclusive
  • For long, from -9223372036854775808 to 9223372036854775807 (-263 to 263 - 1), inclusive
  • For char, from 0 to 65535 inclusive

2. Floating-Point Types, Value Sets, and Values

부동소수점 타입(floating-point types)은 float과 double이 있다. 둘은 각각 개념적으로는 'IEEE 754 표준'에서 규정하는 32-bit single-precision과 64-bit double-precision 포맷이다.

IEEE 754 standard는 +/- 수만 포함하지 않고 +/- 0(제로값), +/-무한값, 그리고 Special Not-a-Number(NaN)값. NaN값은 0/0같은 유효하지 않은 연산의 결과를 표현할 때 쓰인다. 모든 JVM의 구현은 두개의 표준 집합을 지원하는 것이 요구된다. (float value set과 double value set)

returnAddress Type and Values

returnAddress type은 JVM의 jsr, ret 그리고 jsr_w 명령어에서 사용한다. returnAddress의 값은 JVM명령어들의 연산부호의 포인터들이다. 숫자 원시 타입(numeric primitive types)와 달리 returnAddress타입은 어느 자바 프로그래밍 언어 타입과 들어맞지 않고 running program에 수정될 수 없다.

3. boolean Type

비록 JVM이 불린타입을 정의한다 하지만, 아주 제한적인 것만을 지원한다. JVM에는 boolean 값을 위해 만들어진 명령어는 없다. 대신 JVM에 불린값을 int로 바꾸는 어구가 따로 있다. JVM은 boolean arrays는 직접적으로 지원한다. newarray 명령어는 불린타입배열를 만들 수 있다. 불린타입배열은 바이트배열(byte array)의 명령어로 접근되고 수정된다.(baload, bastore) *오라클 JVM의 구현에서는, 불린배열은 JVM 바이트배열로 인코딩 되어있다.(불린요소 하나당 8비트) JVM은 1,0을 인코딩해서 불린배열을 사용한다.(1=true, 0=false) 자바의 불린값이 int타입 값으로 매핑된다.(compiler가 함)

4.Reference Types and Values

reference type에는 3가지가 있다. : class type, array type, interface type 이것들의 값은 각각 동적으로 만들어지는 클래스 인스턴스, 배열 또는 인터페이스를 구현한 클래스 인스틴스 / 배열과 연결된다. 배열타입은 1차원 컴포넌트타입을 구성한다.(???) 배열타입의 컴포넌트 타입은 자기 스스로 배열 타입이다.(???) 만약, 어떤 배열타입에서 시작하면, 하나는 컴포넌트 타입을 고려하고, 그 후에 그 타입의 컴포넌트타입(이것도 배열이라면)을 고려한다. 계...속, 마침에(마지막에) 배열타입이 아닌 컴포넌트타입이 발견된다. 이걸 element type of an array type 이라고 한다. 배열의 요소타입이라고 하자. 이 요소타입은 원시 타입, 클래스 타입, 인터페이스 타입건 상관 없지면 이 이중에 있어야 한다. *여담: 컴포넌트타입은 확장이 가능하니 배열을 확장할 때 component type으로 확장되다가 값이 있는 element type으로 가면 거기서 멈추는 듯. 레퍼런스 값은 null reference를 가질 수도 있다. null reference는 오브젝트가 없음과 연결되어 있다. (null이란 말) null reference는 처음에는 run-time type을 가지지 않는다. 하지만 어떤 타입으로도 캐스팅 될 수 있다. 이 타입의 디폴트 값은 null이다. 이 명세는 구체적인 null 값을 강제하지 않는다.

[jvm]00-Class File Format 클래스파일포맷

jvm 개요

  1. Class File Format

  2. 모든 JVM으로 컴파일된 코드는 class라는 파일포맷으로 변환된다.

  3. Data Types

  4. JVM은 두 가지의 타입을 운영한다. primitive typesreference types이다. 그에 부응하여, 이 두 타입은 서로 방식으로 값을 저장하고, 아규먼트로 다뤄지거나, 리턴값으로 사용되고 또 계산된다. JVM은 대부분의 타입체킹type checking을 런타임 이전에 한다. primitive type의 값들은 이름표가 붙여질 필요가 없어서 알기 힘들 수 있지만, run time에는 타입을 볼 수 있고, 레퍼런스타입의 값으로 구별할 수도 있다.

    JVM도 이런 식으로 알아낼까??? JVM은 명령어 집합이 operand(피연산자)타입을 구별한다. (특정 타입 값을 실행하기 위해서 명령어를 보고 확인한다) 예를들어, iadd, ladd, fadd, dadd 는 모두 JVM에서 수를 더하고 결과값을 생성하는 명령어다. 하지만 각각 특정한 operand type에서만 작동한다. 위의 명령어들은 순서대로 int, long, float, double이다.

    JVM은 오브젝트를 지원한다. (여기서 오브젝트는 동적할당 인스턴스 또는 배열 모두를 말한다.) 오브젝트 레퍼런스(a reference to an object)는 Java Virtual Machine type reference로 간주된다. (그냥 reference type이라 간주된다는 말...?) 레퍼런스타입의 값은 오브젝트의 포인터로 생각해도 좋다. 하나의 오브젝트에 여러개의 오브젝트레퍼런스가 존재할 수 있다. (More than one reference to an object may exist.) 오브젝트는 항상 type reference의 값을 통해서 실행되고, 넘겨지고 테스트된다.(Objects are always operated on, passed, and tested via values of type reference.)

  5. Primitive Types and Values

  6. Java Virtual Machine이 지원하는 primitive data type은 숫자 타입(numeric types), 불린 타입(boolean type), 그리고 리턴어드레스 타입이다.(returnAddress type)

    숫자타입(numberic types)는 정수타입(integral type)과 부동소수점 타입(floating-point type)으로 나뉜다.

    정수타입

    • byte, 8-bit 부호붙은 2의보수 정수(8-bit signed two's-complement integers), 디폴트 0
    • short, 16-bit 부호붙은 2의보수 정수, 디폴트 0
    • int, 32-bit 부호붙은 2의보수 정수, 디폴트 0
    • long, 16-bit 부호없는 정수(16-bit unsigned integers), 유니코드 코드포인트(문자의 바이트코드)를 나타내며, UTF-16으로 인코딩되어있다. 디폴트 null code point('\u0000')

    부동소수점 타입은 IEEE754의 표준을 따른다.

    • float, whose values are elements of the float value set or, where supported, the float-extended-exponent value set, and whose default value is positive zero
    • double, whose values are elements of the double value set or, where supported, the double-extended-exponent value set, and whose default value is positive zero
    • 위 내용을 그냥 적은 이유는 아래에 관련 내용이 제대로 설명될 것 같아. 용어를 남겨 놓는다. (적절한 용어도 뭔지 모르겠음, 그냥 float,double 값들이랑, double-extended-exponent는 지수로 표현되는 값들을 말한다. 디폴트는 양수0으로 같다)

    불린타입(boolean type)은 참 거짓을 true, false로 부호화한다. 디폴트 false.

    • The First Edition of The Java® Virtual Machine Specification did not consider boolean to be a Java Virtual Machine type. However, boolean values do have limited support in the Java Virtual Machine. The Second Edition of The Java® Virtual Machine Specification clarified the issue by treating boolean as a type.

    returnAddress타입은 JVM명령어의 연산부호의 포인터다. primitives type에서 유일하게 Java Programming language type과 직접적으로 연관되어 있지 않다.

윈도우 브라우저 호환성 문제




IE는 우리의 주적이다.


여튼 윈도우즈 브라우저의 호환성 문제를 많이 일으키는 것이 IE인데 그 호환성 문제를 없애려는 미봉책 중 하나를 여기에 적어 놓는다.

http-equiv="X-UA-Compatible" content="IE=edge"
매타테그를 하나 만들어서 그 안에 이것을 넣어라. (사실 메타태그를 다 넣어서 보여주고 싶은데 안보여짐... 계속 사라지고... 정말 메타태그로 인식하는 것 같음.방법을 알아봐야겠지만 귀찮아서 이렇게 보여줌)

[javascript patterns][Namespace Pattern] 스터디 19


Namespace Pattern

다른 언어를 공부해 본 적이 있다면 바로 느낌이 왔겠지만 네임스페이스패턴(Namespace Pattern)은 타 언어에서 네임스페이스를 정하는 것과 비슷한 일을 한다. 가장 중요한 차이는 namespace 혹은 package라는 문법적 이름을 사용하지 않고 구현을 해야 한다는 점이다.

[javascript patterns][Object Creation Pattern] 스터디 18

The JavaScript language is simple and straightforward and often there’s no special syntax for features you may be used to in other languages, such as namespaces, modules,packages, private properties, and static members.
자바스크립트에는 namcespace, module, packages, private properties, static members를 만드는 데 새로운 문법이 있지는 않다. 대신 여러가지 방법으로 구현할 수 있다. (우리는 이 패턴들을 알아야 한다. 다른 언어들이 패키지를 가지고 있듯이 자바스크립트에도 패키지를 가지고 있다. 단지 문법이 제공하는 것이 아닌 우리가 직접 구현해야 한다는 점이 다른 점이다. 그러니 익혀야 한다.)

이번 장에서는 객체화에 관련된 패턴들을 배울 것이다.
  • namespacing
  • dependency
  • declaration
  • module pattern
  • sandbox patterns

[javascript patterns][함수] 스터디 17

지금까지 배운 것을 요약해보자

코드를 더욱 깨끗하게 하는 것은 개발자의 의무이다. javascript는 참으로 깨끗한 코드를 짜기가 힘들다. 그래서 서로다른 js를 만들어서 html에서 따로 관리하는 것이 대부분인 듯하다.
하지만 당신이 API를 만든다면? 이름 하나하나에 많은 공을 들일 것이다. 그리고 이름이 없어지길 원할수도 있다. 그 때 우린 익명함수를 사용한다. 즉시실행함수를 사용하여 전역(ex. window)에 수 많은 라벨들을 없애 깔끔한 코드를 만들도록 한다.
하지만 나는 아직 멀었다. 배우면 배울수록 늘어가는 것이 '내가 모르고 있는 것'들의 양인 것 같다.

[javascript patterns][커리(Curry)] 스터디 16

커링(Curring)

function add(x, y) {
  var oldx = x, oldy = y;
  if (typeof oldy === 'undefined') { // 부분적인 적용
    return function (newy) {
      return oldx = newy;
    }
  }
  // 전체 인자를 적용
  return x + y;
}

//테스트
typeof add(5); // "function"
add(3)(4); // 7

// 새로운 함수를 만들어 저장
var add200 = add(200);
add200(10); // 2010
교재의 예제를 그대로 썼다. add가 반환하는 내부 함수에 클로저를 만든다. 클로저는 x,y의 값을 oldx와 oldy에 저장한다. 하지만 더 간단하게 할 수 있다. 다음 예제를 보자.
function add(x, y) {
  if (typeof y === "undefined") {
    return function (y) {
      return x + y;
    }
  }
  // 전체 인자를 적용
  return x + y;
}
여기에는 oldx, oldy가 없는데 원래 x는 암묵적으로 클로저에 저장되어 있고, y는 재사용을 하고 있다.

조금더 범용적인 방식으로 처리할 수 있을까?

어떤 함수라도 부분적인 매개변수를 받는 새로운 함수로 변형할 수 있을까?
function flexible_curry(fn) {
  var slice = Array.prototype.slice,
      stored_args = slice.call(arguments, 1);

  return function () {
    var new_args = slice.call(arguments),
        args = stored_args.concat(new_args);
    return fn.apply(null, args);
  };
}
되게 복잡해 보이는 이유는 단시 arguments가 배열이 아니기 때문이다. slice를 쓰고 싶은데 arguments는 배열처럼 보일 뿐 배열이 아니기 때문에 var slice = Array.prototype.slice로 slice안에 메소드를 넣었다. 그리고는 slice.call(arguments, 1); argument를 배열의 메소드로 배열처럼 사용하는 것이다. 이해가 안된다면
[1, 2, 3, 4, 5].slice(1); // [2, 3, 4, 5]
Array.prototpye.slice.call([1, 2, 3, 4, 5], 1);
이제 테스트를 해보자
function add(x, y) {
  return x + y;
}
function flexible_curry(fn) {
  var slice = Array.prototype.slice,
      stored_args = slice.call(arguments, 1);

  return function () {
    var new_args = slice.call(arguments),
        args = stored_args.concat(new_args);
    return fn.apply(null, args);
  };
}


var newadd = flexible_curry(add, 5);
newadd(5); // 10
add(fn)는 클로저로서 값이 휘발성으로 사라지지 않는다. (객체화도 되지 않았는데 어떻게?) 그것이 클로저다. 나중에 좀 더 공부해보도록 하자. 어쨋든 argument에서 첫번째 것만을 잘라내서(slice) sotred_args에 넣기 위해 Array.prototype.slice.call(arguments, 1)을 사용하였다.
그리고 반쪽자리 add(fn)를 반환한다. 그것을 newadd에 넣었고 newadd(5)를 실행하면 더하기를 수행 할 것이다. 여기서 concat은 배열끼리의 접합을 수행한 후, args에 넣는다. 그 후 fn.apply(null, args); 를 실행한다. (apply는 call과 비슷하게 동작하지만 배열을 받는 다는 것을 기억하라. 이 예제에서 apply는 아주 잘 맞는다.)
function multifly(a, b, c, d, e) { return a * b * c * d * e; }

function flexible_curry(fn) {
  var slice = Array.prototype.slice,
      stored_args = slice.call(arguments, 1);

  return function () {
    var new_args = slice.call(arguments),
        args = stored_args.concat(new_args);
    return fn.apply(null, args);
  };
}

flexible_curry(multifly, 1, 2, 3)(5, 5);


var a = flexible_curry(multifly, 1.534);
a(10, 10, 10, 10);
var b = flexible_curry(a, 2, 3);
b(6, 7);
커링은 엄청난 자유를 준다.

커링을 사용해야 할 경우

어떤 함수를 호출할 때 대부분의 매개변수가 항상 비슷하다면, 커링의 적합한 후보라고 할 수 있다. 매개 변수 일부를 적용하여 새로운 함수를 동적으로 생성하면 이 함수를 반복되는 매개변수를 내부적으로 젖아하여, 매번 인자를 전달하지 않아도 원본 함수가 기대하는 전체 목록을 미리 채워놓을 것이다.

[javascript patterns][커리(Curry)] 스터디 15

부분적인 적용

함수의 호출이 실제로는 인자의 묶음을 함수에 적용하는 것임을 알 수 있다. 그러면 인자를 한 번에 다 적용하는 것이 아니라 부분부분 인자를 가져와서 함수에 적용하는 것은 어떨까? 이것은 수학 함수를 직접 계산할 때 흔히 쓰는 방법이라 한다.
예를 들어보자
funtion add(x, y) {
  return x + y;
}

add(5, 4);
여기서 부분적인 적용을 하는 개념은
function (5, y) {
  return 5 + y;
}
// 이렇게 x를 먼저 적용한 후에
function (5, 4) {
  return 5 + 4;
}
// 이렇게 나머지 인자가 부분적으로 가져와서 적용하는 것이다.
그러니까 첫번째 인자를 적용한 상태에서 다른 인자를 넣어서 함수를 수행하는 것이다.
var add = function (x, y) {
  return x + y;
}

add.apply(null, [5, 4]); // 9

var add_part = add.partialApply(null, [5]); // 첫번째 인자만 먼저 적용 (부분적용)

add_part.apply(null, [4]); // 9
이것은 사실 add(5)(4)와 같다. add(5)가 (4)로 호출할 수 있는 함수를 반환하기 때문이다. 아! partialApply는 현재 없는 메서드이다. 하지만 이제 만들어 볼 것이다.
함수의 부분적인 적용을 처리하도록 하는 과정을 커링(Curring)이라고 한다.

[javascript patterns][설정 객체 패턴] 스터디 13


설정 객체 패턴

설정 객체 패턴은 좀 더 깨끗한 API를 제공하는 방법이다. 라이브러리나 다른 프로그램에서 사용할 코드를 만들 때 특히 유용하다. 소프트웨어를 개발하고 유지보수하는 과정에서 요구사항이 변경되는 것은 어쩔수 없는 현실이다. 변화하는 요구사항에 우리는 어떻게 코드로 대처해야 할까. addPerson()이라는 함수를 가정해보자. 처음에는 이름과 성만 만들어 사람을 추가하라고 요구를 했다.
function addPerson(first, last) {/*...*/}
갑자기 생일, 성별, 주소 도 저장해야 한다고 한다.(게다가 선택적으로) 선택적으로 저장하는 것을 모르겠고 일단 매개변수를 추가해보자.
function addPerson(first, last, dob, gender, address) {/*...*/} //선택적인 매개변수는 일부러 뒤에 적었다.
함수가 좀 길어졌다. 그런데 username은 필수로 저장해야 한다고 전화가 왔다. 이제 함수를 호출할 때는 필수로 써야 하는 것, 선택적인 매개변수, 그리고 매개변수의 순서... 점점 많아지고 복잡해진다.
addPerson("Younghwan", "Nam", new Date(), null, null, "myID");
많은 수의 매개변수는 참 불편하다. 모든 매개변수를 하나의 객체로 만들어 전달하는 것이 더 낫다. 이 객체를 설정(configuration)을 뜻하는 conf라고 해보자.
var conf = { username: "myID", first: "Bruce", last: "Wayne" };
addPerson(conf);
이 패턴은 함수가 DOM 엘리먼트를 생성할 때, 엘리먼트의 CSS스타일을 지정할 때 유용하다. 엘리먼트와 스타일은 많은 수의 어트리뷰트와 프로퍼티를 가지며 대부분은 선택적인 값이기 때문이다.

2016년 12월 11일 일요일

[Mathematics for Computer Science] Recurrences 재귀

Recurrences 재귀

재귀를 넘어갔다. 여러가지 내용을 보았는데, 사실 올리기가 너무 힘들다. (기호 찾기가 너무 힘들어서... 꼭 그것만은 아닌 것 같고...)
하지만 이번 내용은 꼭 올려놓아야겠다.

The Tower of Hanoi

하노이의탑 문제이다. (위 그림은 교재의 내용을 그대로 가져온 것이다.) 이 문제를 모른다면 구글로 한번 찾아보길 바란다. 일단 3개의 칸을 노가다로 보여주겠다. 그림을 그릴 수는 없는 관계로 내가 보는 교재에서 나오는 그림을 본뜨겠다.
숫자는 각각의 탑과 그 탑의 크기라고 보면 된다. 바로 위에 보이는 그림은 탑 전체가 이동하기 위해 움직여 온 발자취 같은 것이다. 총 7번을 움직였다. 잘 기억하자 3개의 탑이 움직이는데 일.곱.번. 움직였다.

Finding Recurrence

자! 하노이의 탑에서 재귀적인 움직인이 있는지 없는지 찾아봐야 한다. 탑이 n층으로 이루어져 있다 가정하고, 탑이 옆으로 이동할 때 몇번 움직일까? 이것을 T(n) 이라 하자. 일단 3개의 탑이 옆으로 이동하는 것으로 시작해보자( T(3) ). 어떤 규칙이 있는가? 일단 3번이 움직이려면 1,2번이 움직여야 한다. 그리고 3번이 움직이고 또 1,2번이 움직여서 3번 위로 올라탄다. 잠깐! 1,2번은 마치 2층으로 이루어진 탑과 같다.( T(2) ) T(3) = 2 * T(2) + 1 이렇게 된다. 그리고 이것은 T(n) = 2 * T(n-1) + 1 이런 공식을 유추 한다. 이게 맞는 걸까? 한번 T(2)을 예로들어보자. T(2) = 2 * T(1) + 1 = 2 * 1 + 1 탑이 달랑 하나 있을 때( T(1) )는 한 번만 움직이면 될 것이다.

이렇게 하면 끝인가? 아니다. 확인해보자. 위의 공식에 대한 여러가지 확인(?) 아니 증명법이 있는데 그것들은 다음 시간에 보도록 하자. 오늘 여러분이 알아가야 할 것은 이 공식하나.
T(n) = 2T(n-1) + 1

2016년 12월 10일 토요일

[clojure] ref 사용하기



ref

이전 시간에 atom을 공부했다. 그런데 왜 ref라는게 필요할까? 값을 보호하는데 atom 하나만 있으면 되는거 아닌가? 하지만 여러개의 행위를 트랜잭션처럼 묶고싶다면? ref를 쓰는 것이 좋다.
user=> (def items
  #_=>   #{"backpack" "phone" "card" "water" "dairy"})
#'user/items
user=> (defn item-count [item count]
  #_=>   {:name item :count count})
#'user/item-count


user=> (def shelves (ref {:name "YH Market" :items 
         (set (map #(item-count % (rand-int 10)) items))}))
#'user/shelves
user=> shelves
#object[clojure.lang.Ref 0x7b5ff2de 
{:status :ready, :val {:name "YH Market", :items #{{:name "backpack", :count 0} 
{:name "card", :count 7} {:name "phone", :count 7} {:name "dairy", :count 8} 
{:name "water", :count 6}}}}]
user=> (:name shelves)
nil
user=> (:name @shelves)
"YH Market"
user=> (:items @shelves)
#{{:name "backpack", :count 0} {:name "card", :count 7} 
{:name "phone", :count 7} {:name "dairy", :count 8} {:name "water", :count 6}}

user=> (defn buy [shelves] (dosync
  #_=>   (when-let [goods (some #(if (> (:count %) 0) %) (:items @shelves))]
  #_=>     (let [updated-goods (item-count (:name goods) (dec (:count goods)))]
  #_=>       (alter shelves update-in [:items] disj goods)
  #_=>       (alter shelves update-in [:items] conj updated-goods)))))
#'user/buy
user=> (buy shelves)
{:name "YH Market", :items #{{:name "phone", :count 2} {:name "dairy", :count 8} 
{:name "card", :count 5} {:name "water", :count 6} {:name "backpack", :count 2}}}
user=> (buy shelves)
{:name "YH Market", :items #{{:name "phone", :count 1} {:name "dairy", :count 8} 
{:name "card", :count 5} {:name "water", :count 6} {:name "backpack", :count 2}}}
진열대를 만들고 거기에 item를 넣는다. 그리고 그 갯수는 임의로(0부터 10까지) 정했다. (buy shelves)로 하나를 사면? 하나가 사라진다. (문제는 대충 만들어서 물건을 고를 수 없음 ㅎㅎ..)

[clojure] atom



왜 아톰이라는 것이 존재 하는가.
user=> (def a 1)
#'user/a

user=> (inc a)
2

user=> a
1

user=> (def b (inc a))
#'user/b

user=> b
2
느껴지는가? a는 한번 정의되면 바뀌지 않는다. 대신 새로 정의해야한다. 옛 철학자들은 수를 신처럼 받아들이기도 했다. 값은 변하지 않는다. 이건 불변의 진리다. int a = 0; a++; 이걸 사용하면서 값이 변한다고 믿어왔는가? 값이 변했다고 생각하지만 값은 변한것이 아니다. 시간이 변했을 뿐. 값은 새로 창조되었다. 뭐 이런 이야기로 해도 실재 세상에서도 한 곳에서 값이 변해야 하는 상황이 있다. 그럴때 atom을 사용하는 것이다.
user=> (def my_atom (atom 0))
#'user/my_atom
user=> @my_atom
0
user=> (swap! my_atom inc)
1
user=> @my_atom
1
대충 무슨 짓을 했는지 알기 바란다. (atom 0)으로 아톰을 생성했고, @를 붙여서 아톰의 값을 한번 봐보았다. 그리고 swap! 이놈으로 값을 변화시켰다. 그리고 다시 @로 값을 보면??? 값이 변했다!! 이 외에도 다른 방법으로 변화를 시키는 애가 있다.
(reset! my_atom 0)
0
@my_atom
0

[clojure] 검증자 (validator)



validator

검증자(validator)는 어떤 상태를 참조로 써도 좋은지 정한다.
만약 10을 넘으면 안되게 하는 validator를 만들어보자.
(defn max-ten-validator
  [{:keys [number]}]
  (< number 10))

(def n
  (atom
    {:number 0 :name "Younghwan"}
     :validator max-ten-validator))

user=> (swap! n update-in [:number] + 3)
{:number 3, :name "Younghwan"}
user=> (swap! n update-in [:number] + 3)
{:number 6, :name "Younghwan"}
user=> (swap! n update-in [:number] + 3)
{:number 9, :name "Younghwan"}
user=> (swap! n update-in [:number] + 3)
IllegalStateException Invalid reference state  clojure.lang.ARef.validate (ARef.java:33)

[clojure] date time 날짜 시간



Clojure Date/Time

본 내용은 tutorialspoint를 보고 거의 똑.같.이. 정리한 것이다. 자바를 아십니까? 이 3가지를 이용하여 시간을 뽑아보자. 1 Java.Util.Date 2 java.text.SimpleDateFormat 3 getTime

1. Java.Util.Date

(def date (.toString (java.util.Date.)))

(println date)
"Fri Dec 09 11:21:14 KST 2016"

2. SimpleDateFormat

(def date2 (.format (java.text.SimpleDateFormat. "MM/dd/yyyy") (new java.util.Date)))

date2
"12/09/2016"

3. getTime

(import java.util.Date)

(def date (.getTime (java.util.Date.)))

date
1481251602775

2016년 12월 8일 목요일

[clojure-docs]update-in



update-in

(update-in m [k & ks] f & args) 도큐먼트내용처럼 내용을 바꾼다.(update) 첫번째 아규먼트는 바꿀 자료구조(m) 그 다음은 자료구조 안에 있는 키값([k & ks]) 그리고 f 는 키 값에 걸리는 놈을 실행할 함수! 그 뒤는 그 함수에서 사용할 아규먼트!
(def here {:name "Younghwan" :age 26})
(update-in here [:age] * 10)
{:name "Younghwan", :age 260}
이해 되었길 빈다.

2016년 12월 7일 수요일

[clojure-docs]add-watch



add-watch

나는 클로저에 대해 많이 관심이 많다. 그런데 이 watch에 대해 제대로 알지는 못한다. 내가 아는 것은 watcher로 해당 원자값의 상태를 지속적으로 확인한다는 것이다. 그 시작은 watcher를 더하는 것으로 시작되는 것이다. 관찰(watch)는 인자 네 개를 받는 함수이다. 1. 키 2. 관찰되는 참조 3. 이전 상태 4. 새로운 상태 이것이다. 링크에 있는 첫번째 문장을 보자. Adds a watch function to an agent/atom/var/ref reference. The watch fn must be a fn of 4 args: a key, the reference, its old-state, its new-state. 일단 보면 모르겠는데 일단 이상한 보면 무슨 느낌인지 알 것이다.
(def at (atom 0)) 
#'fwpd.core/at

(add-watch at :watcher
  (fn [key atom old-state new-state]
    (println "The valueof the atom has been changed")
    (println "key is " key)
    (println "atom is " @atom)
    (println "old-state is " old-state)
    (println "new-state is " new-state)
    (if (> new-state 10)
      (println "TOO BIG!!!!!!")
      (println "HAHA"))))
#object[clojure.lang.Atom 0x20788a98 {:status :ready, :val 0}]
자 아톰을 생성했다. 아톰이 뭔지 모른다고? 그냥 값이라고 생각하자. 그런데 아주 안전한 값이다. 그래서 단순히 값을 변경할 수 없다. 바꾸려면 특정 함수를 써야 하는데 그것은 swap! 이다. 중요하기 때문에 느낌표까지 붙어있다. 기억하자. 일단 실행해보겠다.
(swap! at inc)
The valueof the atom has been changed
key is  :watcher
atom is  1
old-state is  0
new-state is  1
HAHA
1
;;10까지 올려보자
(swap! at inc)
The valueof the atom has been changed
key is  :watcher
atom is  11
old-state is  10
new-state is  11
TOO BIG!!!!!!
11
무엇이 바뀌었는가??? HAHA 에서 TOO BIG!!!!!! 으로 바뀌었다. 바로 watcher가 이렇게 계속 관찰해서 반응한 것이다.

[clojure-docs]merge-with



merge-with

말처럼 합치는 것이다(merge). 그런데 합치면서 무얼하는 것(with)이다. 링크에 있는 내용을 보면서 위에 한 문장을 곱씹자.
(merge-with + {:a 1 :b 1 :c 1} {:a 10 :c 13})
{:a 11, :c 14, :b 1}
이렇게 병합하면서(merge) 더한다.(with)

2016년 12월 4일 일요일

NodeSchool 워크숍 참석기

10월 29일 노드스쿨 워크숍


지난 10월 29일 노드스쿨 워크숍에 갔었다. 노드제이에스가 대체 뭐가 그리 중헌디. 이 난리 인가 하여 참석하기로 결심했다.


수 많은 사람들이 워크샵에 참석했는데 그 중에 초등학생 정도의 아이들도 참석을 하고 있어서 당황했다.

오전에는 Javascript 문법을 잠시 다루고, 오후에는 Node.js에 대해서 훑어보았다. node school에서 제공하는 교육 프로그램이 있는데 해당 프로그램에 나오는 문제들을 풀다보면 (완전히 이해된 것은 아니지만) 조금 더 자바스크립트와 Node.js에 친근해진 느낌을 받을 수 있었다.

아쉬운 점은 javascript 강의와 node.js강의에 난의도의 갭이 있었는데 처음 배우는 사람들도 이 워크숍을 오면 배울 수 있는 것처럼 강의를 했지만 그렇지 않았던 것 같다. javasciprt는 말그대로 변수를 넣고 반복문을 사용하고 제어문을 사용하는 이러한 단순한 것들이었지만 node.js에서는 일부러 어렵게 가르치려고 하는 느낌을 지울 수 없었다.(우린 이렇게 스마트하다) 그때부터 이해를 잘 할 수 없었다. (어려웠다기보다는 설명하지 않고 자랑을 하고 있을 뿐이었다)
node.js를 설명하는 것이 아닌 node.js에서 자바의 새로운 지평을 열 기술들을 설명하면서
'요즘은 이렇게 코딩합니다.' promise도 이제 예전말이지요.' 
하면서 계속 코딩방식을 바꿔가면서 현란하게 코딩을 한다.

어려운 내용이 나오니 Node.js를 다루는 경력자인 듯한 분들이 점점 질문을 한다.  워크샵은 강사와 경력자들의 질의시간이 되었고 처음 노드를 접한 사람들에게는 의미 없는 시간이 되었다.
사람들이 점점 나가기 시작했다. 사람들이 나갈 수록 더욱 빠르게 진도를 나갔다. 다들 숨죽여서 타입핑하고 머리를 짜내면서 집중한다. 세미나가 끝나고 다들 기진맥진한 모습이 역력했다. 집에 돌아오는 길이 가볍지는 않았다.

나만 그랬던 것이 아니었던 모양이다.  그리고 노드스쿨 측도 워크샵 참가자들에게 후기를 듣고 조치가 필요한(?) 듯 노드스쿨이 전 강의에 대한 보충 수업 같은 것을 하는 다른 워크샵을 개최하기로 한다는 메일이 왔다.

나는 신청하지 않았다.
생활코딩의 이고잉님 만세

2016년 12월 3일 토요일

[Mathematics for Computer Science]그래프이론을 들어가며....

드디어 본 책의 챕터빠이브!!! Number Theory를 끝냈다. Number Theory는 한참 전에 끝냈지만 그래프이론으로 들어가기가 무서웠다. 진도가 느리게 나갔지만 블로그를 보면 알듯 나는 이 수학 공부만 하지는 않았다. clojure라는 것이 궁금하여 이것저것 만져보기도 하였고, Java관련 내용도 가끔 올렸으며, javascript 또한 정리를 하기도 하였으며 등등 여러 일들을 했다.
Number Theory를 공부하면서 익힌 것은 "내가 무엇을 모르는가" "다음에는 내가 무엇을 더 공부해야 되겠다."는 생각이 들었을 뿐이었다. 원서를 읽어서 더욱 어려웠을 수도 있겠다. 그래서 이해가 되지 않는 점들을 교보문고에 가서 읽어보았다. 
똑같았다.
영어로 이해가 되지 않았던 것들은 한국말로도 이해가 되지 않았다. 단지 읽기가 더 편하여서 '내 머리가 이해했을걸? 방금 한국말이 들어왔잖아' 라고 편안하게 다음 문장을 읽고 있었다. 사실은 하나도 이해하지 않았는데...
기억에 남는 내용은 [자연수의 정렬성]에 관련된 내용인데 해당 내용은 아무리 생각해도 완벽하게 이해가 되지는 않았다. 그냥 "아... 이런게 자연수의 정렬성이구나..." 정도의 느낌인데, 이것도 맞다고 할 수는 없겠다. 모르는 것이 나올 때마다 낙서하고 포스트잇으로 붙이기도 하고 때론 노트를 찢어서 풀로 붙여가면서 나름 공부를 열심히 했는데, 진심으로 집중하지 못했던 시간이 부족했던 것 같아 아쉽다.
빨리 빨리 넘어가서 다음 책도 읽을 날이 왔으면 좋겠다.

2016년 12월 2일 금요일

[Java Reflection REVIEW] 자바 리플렉션 사용기- 02




JAVA REFLECTION

What if You need to transfer Object to Map which means You are going to relocate your Object's private members to a Map. ALL. previously, We've seen how to do this. I would assume that you've already had my code in first '[Java Reflection REVIEW]자바리블렉션 사용기 -01'
Info info = new Info("name", "password", "alias", "address", "strength",
                     "etc1", "etc2");
ObjectToMap(map, Arrays.asList("name", "password", "alias",
 "address", "strength", "etc1", "etc2"), info);
But I want to code like this! Because always all of members in Info move into a Map.
ObjectToMap(map, info);
How is it possible. We'll use Reflection and collect perticular methods (which are getters) in invoke them. Firstly, make a method called "ObjectToMap"
private void ObjectToMap(Map map, Object sms) {
  List methods = getGetters(getMethods(sms), sms);
  for ( Method method : methods) {
    map.put(CamelToSnake(dropGet(method.getName())), invokeMethod(method,sms));
  }
}
You can see there is a for loop statement. We will get getMethods in Object via getGetters(); Second, create getGetters
private List getGetters(final Method[] methods, Object obj) {
  int len = methods.length;
  List res = new ArrayList();
 
  for(int i = 0; i < len ; i++) {
    if(methods[i] != null && methods[i].getName().startsWith("get") &&
            !methods[i].getName().endsWith("Class") ) {
      res.add(methods[i]);
    }
  }
  return res;
}

private Method[] getMethods(Object sms) {
  return sms.getClass().getMethods();
}
finally, INVOKE!!!!
private String invokeMethod( Method method, Object sms) {
  String res = null;
  try {
    res = String.class.cast(method.invoke(sms));
   
  } catch (Exception e) {
    e.printStackTrace();
  }
  return res;
}
You can test easily. I hope you enjoy my text. Your comments will help me blog. Thank you.