Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Soufflé로 논리 요리하기

Soufflé는 프로그램 분석과 지식 표현을 위해 설계된 효율적인 Datalog 엔진입니다. 이 튜토리얼에서는 컴포넌트 매개변수화와 대수적 데이터 타입을 포함하여 Soufflé의 기본 기능과 고급 기능을 살펴보겠습니다.

Soufflé가 설치되어 있는지 확인하십시오. Soufflé GitHub 저장소에서 내려받아 설치 안내를 따르면 됩니다.

Datalog는 데이터 질의와 변환을 정의하기 위한 선언형 언어입니다. 특히 패턴 매칭과 재귀적 데이터 처리에 유용합니다. Datalog를 처음 접한다면 간단한 예제부터 시작하는 것이 도움이 될 것입니다.

// Simple example: Relationships
.decl parent(x: symbol, y: symbol)
.decl ancestor(x: symbol, y: symbol)

parent("Alice", "Bob").
parent("Bob", "Charlie").
parent("Charlie", "David").

ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).

이 예제에서는 다음을 수행합니다.

  • parent 관계를 정의합니다.
  • 재귀를 사용하여 ancestor 관계를 도출합니다.

프로그램을 실행하려면 코드를 family.dl이라는 파일에 저장한 다음 다음 명령을 실행하십시오.

souffle family.dl

Souffle는 컴포넌트 매개변수화와 대수적 데이터 타입 같은 표준적인 함수형 프로그래밍 기능을 지원합니다.

컴포넌트 매개변수를 사용하면 Soufflé에서 재사용 가능한 모듈을 만들 수 있습니다. 비슷한 구조를 사용하되 매개변수만 다르게 하여 두 그래프를 분석하려는 상황을 생각해 봅시다.

graph.dl이라는 Datalog 파일을 만드십시오.

.decl edge(X: symbol, Y: symbol)
.decl reach(X: symbol, Y: symbol)

edge("A", "B").
edge("B", "C").
edge("C", "D").

reach(X, Y) :- edge(X, Y).
reach(X, Y) :- edge(X, Z), reach(Z, Y).

이제 같은 컴포넌트를 참조하면서 각각을 별도의 Datalog 파일로 저장하여 여러 그래프를 쉽게 만들 수 있습니다.

Soufflé는 합 타입과 곱 타입 같은 대수적 데이터 타입도 지원합니다. 이 기능을 사용하면 복잡한 자료 구조를 모델링할 수 있습니다.

합 타입

합 타입은 여러 형태 중 하나를 취할 수 있는 값을 나타냅니다. 다음은 도형을 나타내는 합 타입의 예입니다.

.type Shape = Circle {radius: float} | Square {side: float}
.decl shape_instance(name: symbol, shape: Shape)
.output shape_instance

shape_instance("Circle1", $Circle(3.0)).
shape_instance("Square1", $Square(2.5)).

곱 타입

곱 타입은 여러 값을 하나로 묶습니다. 다음은 2차원 점을 나타내는 곱 타입의 예입니다.

.type Point = [x: float, y: float]
.decl point_instance(name: symbol, p: Point)
.output point_instance

point_instance("Point1", [1.0, 2.0]).
point_instance("Point2", [3.5, 4.5]).

모듈

컴포넌트 매개변수화와 대수적 데이터 타입을 결합하면 더 복잡한 구조를 만들 수 있습니다. 도형과 점 정의를 하나의 재사용 가능한 컴포넌트로 결합할 수 있습니다.

.type Shape = Circle {radius: float} | Square {side: float}
.type ShapeParam = [name: symbol, shape: Shape]

.decl shape_instance(param: ShapeParam)
.output shape_instance
shape_instance(["Circle1", $Circle(3.0)]).
shape_instance(["Square1", $Square(2.5)]).

Soufflé는 기본 기능 외에도 컴포넌트 매개변수화와 대수적 데이터 타입 같은 고급 기능을 지원합니다. 컴포넌트는 Standard ML의 생성적 모듈(generative module)과 매우 비슷하게 동작하며 타입으로 매개변수화할 수 있습니다.

.comp Catalog<T> {
    .type ItemID <: T
    .decl item(id: ItemID, title: symbol, author: symbol)
    .decl borrower(id: symbol, name: symbol)
    .decl borrowed(item_id: ItemID, borrower_id: symbol, due_date: symbol)

    .decl overdue(item_id: ItemID, borrower_id: symbol, days_overdue: number)
    overdue(ItemID, BorrowerID, DaysOverdue) :-
        borrowed(ItemID, BorrowerID, DueDate),
        to_number(DueDate) < to_number("2024-03-01"),  // Assuming current date is 2024-03-01
        DaysOverdue = to_number("2024-03-01") - to_number(DueDate).

    .decl popular_item(id: ItemID, borrow_count: number)
    popular_item(ItemID, count(BorrowerID)) :-
        borrowed(ItemID, BorrowerID, _),
        count(BorrowerID) > 1.
}

.init BookCatalog = Catalog<symbol>
.init MovieCatalog = Catalog<number>

BookCatalog.item("B001", "1984", "George Orwell").
BookCatalog.item("B002", "To Kill a Mockingbird", "Harper Lee").
BookCatalog.borrower("U001", "Alice").
BookCatalog.borrower("U002", "Bob").
BookCatalog.borrowed("B001", "U001", "2024-02-15").
BookCatalog.borrowed("B002", "U002", "2024-02-20").
BookCatalog.borrowed("B001", "U002", "2024-03-05").

MovieCatalog.item(1, "The Godfather", "Francis Ford Coppola").
MovieCatalog.item(2, "Pulp Fiction", "Quentin Tarantino").
MovieCatalog.borrower("U003", "Charlie").
MovieCatalog.borrower("U004", "David").
MovieCatalog.borrowed(1, "U003", "2024-02-25").
MovieCatalog.borrowed(2, "U004", "2024-02-28").
MovieCatalog.borrowed(1, "U004", "2024-03-10").

.decl overdue_books(id: symbol, borrower: symbol, days_overdue: number)
.output overdue_books
overdue_books(ID, Borrower, Days) :- BookCatalog.overdue(ID, Borrower, Days).

.decl popular_movies(id: number, borrow_count: number)
.output popular_movies
popular_movies(ID, Count) :- MovieCatalog.popular_item(ID, Count).

원문 © Stephen Diehl, stephendiehl.com · 글 CC BY-SA 4.0, 코드 MIT · Stephen Diehl은 런던의 소프트웨어 엔지니어이자 작가입니다(저자가 정한 소개 문구). 이 글은 저자가 개인 자격으로 쓴 것이며 어떤 조직과의 연관도 밝히거나 암시해서는 안 됩니다 (라이선스와 고지).
이 페이지는 원문을 한국어로 옮기며 변경한 비공식 번역이며 같은 CC BY-SA 4.0으로 제공합니다 · yeokja 한국어 번역 · Anthropic 사의 claude-opus-5-5 모델을 활용하여 번역되었으며 학습을 모두 비허용한 상태로 작업하였습니다.