2P by neo 6달전 | favorite | 댓글 1개

K 언어로 생각하기

  • K 프로그래밍은 대부분 REPL을 통해 이루어짐.
  • ngn/k의 rlwrap은 화살표 키로 이력을 탐색할 수 있어 큰 프로그램 개발에 유용함.
  • 함수는 REPL에서 테스트 후 실제 코드로 옮겨짐.
  • ngn/k의 예쁜 출력은 항상 유효한 K 데이터를 반환하며, 프로그램 속도 향상을 위해 미리 계산할 수 있음.
  • K 스크립트는 REPL에 입력한 것처럼 실행되며, 각 줄의 반환값이 세미콜론으로 끝나지 않는 한 출력됨.
  • 스크립트는 다중 라인 정의를 허용하여 가독성에 도움이 됨.
  • 작업을 스크립트에 저장하고 REPL에서 사용하려면, \lfile.k를 사용하여 파일을 실행하고 데이터를 로드할 수 있음.
  • REPL에 파일을 여러 번 로드하여 이전 데이터를 덮어쓸 수 있음.
  • \로 접근하는 REPL 도움말에는 다양한 유용한 명령어가 있음.

배열 프로그래밍의 단순화

  • 배열 프로그래밍은 복잡한 패턴을 더 작고 선언적이며 읽기 쉬운 패턴으로 단순화하는 지속적인 과정임.
  • 복잡한 패턴을 단순화하는 방법은 "APL에서의 패턴과 안티패턴: 초심자의 고원을 탈출하기 - Aaron Hsu - Dyalog '17"에서 자세히 논의됨.

행렬 곱셈의 K 변환

  • 위키피디아 기사에서 가져온 행렬 곱셈의 반복 알고리즘을 K로 직접 변환할 수 있음.
  • K로 변환한 최악의 코드 예시는 많은 전역 변수 할당, 중첩 루프, 많은 수정이 필요함.
  • 코드를 단순화하여 이러한 문제들을 하나씩 해결할 수 있음.

내부 루프의 단순화

  • 내부 루프에서 sum을 fold(/)를 사용하여 단순화할 수 있음.
  • ' (each)는 배열을 반환하므로 C 전역 변수를 제거할 수 있음.
  • i, j, k 변수를 제거하여 루프를 단순화할 수 있음.

루프 제거 및 전역 변수 최소화

  • k 없이 직접 행과 열을 매칭하여 중간 루프를 제거할 수 있음.
  • j를 제거하기 위해 B의 각 열을 A[i]와 짝지을 수 있음.
  • i를 제거하기 위해 eachleft를 사용하여 A의 각 행을 B의 각 열과 짝지을 수 있음.
  • 전역 변수가 더 이상 필요 없음.

행렬 곱셈 함수의 최종 형태

  • + (전치)는 비용이 많이 들므로 제거할 수 있음.
  • x의 각 행을 y의 각 열과 곱하는 대신, B의 각 행을 A 전체에 맞춰 암시적으로 동일한 작업을 수행할 수 있음.
  • 최종적으로 간결하고 명시적인 행렬 곱셈 함수를 얻을 수 있음.
  • 코드를 단순화하는 과정은 처음에는 여러 단계를 거치지만, K에서의 숙련도가 높아질수록 더 쉽고 직관적으로 될 수 있음.
  • 행렬 곱셈은 K의 배열 지원과 잘 맞는 간단한 절차임.
  • K와 잘 맞지 않는 더 많은 알고리즘과 그 처리 방법을 미래 장에서 살펴볼 예정임.

GN⁺의 의견

  • 이 글은 K 언어를 사용하여 행렬 곱셈과 같은 알고리즘을 어떻게 단순화하고 최적화할 수 있는지를 보여줌.
  • REPL을 통한 즉각적인 피드백과 코드의 반복적 개선은 K 프로그래밍의 핵심적인 특징으로, 초급 소프트웨어 엔지니어에게도 유용한 학습 방법임.
  • 코드 단순화 과정은 프로그래밍 능력을 향상시키는 데 중요하며, 이 글은 그 과정을 구체적인 예시를 통해 이해하기 쉽게 설명함.
Hacker News 의견
  • 배열 언어의 유용성과 이해 가능성에 대해 여러 사람들이 의문을 제기하고 있음.

    • 배열 언어는 모든 문제에 적합하지 않음.
    • 많은 유형의 문제에 대해 놀라울 정도로 유능함.
    • 배열 언어 사용자들은 대체로 매우 똑똑함.
    • 배열 언어의 작동 방식을 배우는 것은 큰 도전임.
    • 배열 언어에서 "절차적" 코드를 작성하는 것은 매우 나쁜 일임.
    • 암시적 프로그래밍(tacit programming)의 이해는 정신을 확장시키는 멋진 경험임.
    • 동사 연쇄(verb trains)를 내면화할 때의 경험.
    • 배열 기반 언어가 모든 차원의 배열을 다루는 방식의 이해.
    • "under"의 작동 방식 이해.
    • 함수 지수(function exponents) 작동 방식 이해.
  • 배열 언어의 놀라운 측면이 많으며, 위의 목록은 그중 일부에 불과함.

    • Aaron Hsu가 병렬 APL 컴파일러를 개발하는 과정을 보며 배열 언어의 실제 잠재력을 확신하게 됨.
    • APL 코드의 "의미 밀도(semantic density)"에 대한 논의.
  • 배열 프로그래밍에 대해 들어본 적이 없고 소개를 원한다면 "The Array Cast" 추천.

  • 70년대에 APL/APL2를 발견하고 반했지만, 함수를 구성하는 능력에 더 매력을 느낌.

    • Haskell은 순수하고 타입화되어 있어 APL보다 더 재미있고 강력함.
    • APL의 "사고의 도구로서의 표기법"은 과도한 간결함을 정당화하는 논리로 보임.
  • 배열 언어 사용에서 가장 중요한 깨달음:

    • 동사는 알고리즘임.
    • 동사(또는 부사)의 연속은 사용해본 가장 직접적인 구성 방식임.
    • 프로그램은 문장과 표현의 집합이 아니라 알고리즘의 구성임.
    • 배열, 맵, 함수에 걸쳐 도메인과 범위를 일관되게 다루는 개념.
    • 코드를 읽을 때 눈이 "뛰어다닐" 필요가 없는 왼쪽에서 오른쪽으로의 평가.
    • 데이터에 코드를 보내는 것이 가능하며 선호됨.
    • K 언어의 추가 이점: 뷰(즉, 의존성)를 직접 구현할 수 있고, 인터프리터를 통한 핫 코드 로딩이 가능함.
  • 배열 언어에 대한 질문: "N보다 작은 숫자 중에서 조건 P가 참인 모든 숫자를 찾기"와 같은 작업을 어떻게 수행하는가?

    • 배열 언어에서는 일반적으로 1부터 N까지의 배열을 생성하고, 배열에 대해 조건을 테스트한 후, 조건이 참인 요소만 얻기 위해 마스크를 적용함.
    • N이 크고 조건이 자주 참이 아닐 경우, 불필요하게 많은 임시 배열을 생성하는 것은 메모리와 자원 낭비로 보임.
    • 배열 언어의 구현은 이러한 문제를 최적화하거나, 게으른 평가(lazy evaluation)와 같은 기법을 사용하여 해결할 수 있음.
  • J 언어에 대한 경험: 배열 언어의 패러다임이 편향되어 있으며, 모든 문제를 배열의 중첩으로 생각하는 것이 도움이 되는지 확신할 수 없음.

    • 문제를 단순화할 수 있는 데이터 구조를 자유롭게 생성하는 것이 알고리즘 부분을 크게 단순화할 수 있음.
    • APL/J/K를 사용하기 위해서는 이러한 편향 때문에 더 똑똑해야 함.
  • K 언어 문제를 풀면서 얻은 인상: K 언어는 의도적으로 난해함.

    • 퍼즐과 영리한 해결책에 적합한 언어지만, Python에서 numpy 배열로 작업하는 것이 배열 언어를 배우고 배열로 생각하는 방법을 가르쳐줌.
  • 배열 언어 J의 예시: dot =: +/ . *를 사용하여 P와 Q의 점곱(dot product)을 계산함.

  • K 언어의 문법이 더 짧지만, K 언어의 작동 방식에 대한 많은 내장된 맥락을 머릿속에 유지해야 함.