데이터베이스와 함수형 프로그래밍이 맞지 않는가?


122

나는 한동안 웹 개발자였으며 ​​최근에 함수형 프로그래밍을 배우기 시작했습니다. 다른 사람들과 마찬가지로 저는 이러한 개념 중 많은 부분을 전문 작업에 적용하는 데 상당한 어려움을 겪었습니다. 저에게있어 주된 이유는 무국적 상태를 유지하려는 FP의 목표 사이의 충돌이 제가 수행 한 대부분의 웹 개발 작업이 매우 데이터 중심적인 데이터베이스에 크게 묶여 있다는 사실과 상당히 상충되는 것 같습니다.

OOP 측면에서 저를 훨씬 더 생산적인 개발자로 만든 것은 MyGeneration d00dads for .Net, Class :: DBI for perl, ActiveRecord for ruby ​​등과 같은 객체 관계형 매퍼의 발견이었습니다. 하루 종일 insert 및 select 문을 작성하고 데이터를 개체로 쉽게 작업하는 데 집중합니다. 물론 파워가 필요할 때도 SQL 쿼리를 작성할 수 있었지만 그렇지 않으면이면에서 멋지게 추상화되었습니다.

이제 기능 프로그래밍으로 전환하면 링크와 같은 많은 FP 웹 프레임 워크 에서이 예제 와 같이 많은 상용구 SQL 코드를 작성해야하는 것처럼 보입니다 . Weblocks는 조금 더 좋아 보이지만 데이터 작업을 위해 일종의 OOP 모델을 사용하는 것 같으며이 예제 에서와 같이 데이터베이스의 각 테이블에 대해 수동으로 코드를 작성해야합니다 . 이러한 매핑 함수를 작성하기 위해 일부 코드 생성을 사용한다고 가정하지만 이는 확실히 리스프와 같지 않은 것 같습니다.

(참고로 Weblocks 또는 링크를 자세히 살펴 보지 않았습니다. 사용 방법을 오해하고있을 수 있습니다.)

따라서 질문은 웹 응용 프로그램의 데이터베이스 액세스 부분 (매우 큰 것으로 생각됨) 또는 SQL 데이터베이스와의 인터페이스가 필요한 기타 개발의 경우 다음 경로 중 하나를 강제로 내리는 것 같습니다.

  1. 함수형 프로그래밍을 사용하지 마십시오
  2. 많은 수의 SQL 또는 SQL과 유사한 코드를 수동으로 작성해야하는 성가신 비 추상적 인 방식으로 데이터에 액세스합니다.
  3. 함수형 언어를 의사 OOP 패러다임으로 강제하여 진정한 함수형 프로그래밍의 우아함과 안정성을 일부 제거합니다.

분명히 이러한 옵션 중 어느 것도 이상적이지 않습니다. 이러한 문제를 피할 수있는 방법을 찾았습니까? 여기에 정말 문제가 있습니까?

참고 : 저는 개인적으로 FP 전면에서 LISP에 가장 익숙하므로 예제를 제공하고 여러 FP 언어를 알고 싶다면 lisp가 선호되는 언어 일 것입니다.

추신 : 웹 개발의 다른 측면과 관련된 문제는 이 질문을 참조하십시오 .



4
ClojureQL 및 HaskellDB를 확인하십시오. 관계형 대수를 활용하는 추상화 계층입니다.
Masse 2011-08-05

10
당신은 잘못된 전제에서 시작하고 있습니다. 함수형 프로그래밍은 모두 명시적이고 깔끔하게 상태를 관리하는 것입니다. 사실 그들은 데이터베이스와 매우 잘 작동합니다.
Lucian

3
SQL은 가장 성공적인 기능 프로그래밍 중심 언어 중 하나이며 내재적 인 어려움은 없다고 생각합니다.
Douglas

3
당신의 # 2와 # 3은 잘못된 이분법입니다. 원시 SQL을 작성하는 것은 반드시 피해야 할 일이 아니며 데이터베이스에 대한 추상화가 반드시 OOP와 같을 필요는 없습니다.
Dan Burton

답변:


45

우선 CLOS (Common Lisp Object System)가 "의사 -OO"라고 말하지 않겠습니다. 일등 OO입니다.

둘째, 필요에 맞는 패러다임을 사용해야한다고 생각합니다.

함수는 데이터의 흐름이며 실제로 상태가 필요하지 않은 동안 상태 비 저장 데이터를 저장할 수 없습니다.

여러 가지 요구 사항이 혼합 된 경우 패러다임을 혼합하십시오. 도구 상자의 오른쪽 아래 모서리 만 사용하도록 제한하지 마십시오.


3
재미로, 나는 더 상태 비 저장 데이터베이스가 되려고하는 데이터 로그를 언급 할 것이라고 생각했습니다. "사용자가 게시물 1233을 좋아함"과 같은 모든 작업을 기록합니다. 이러한 작업은 데이터베이스의 실제 상태를 확인합니다. 핵심은 쿼리가 변형이 아니라 사실이라는 것입니다 ...
Chet

80

데이터베이스 전문가의 관점에서 보면 프론트 엔드 개발자는 객체 지향적이거나 기능적이지 않지만 관계형이며 사용하는 데이터베이스를 사용하는 가장 효과적인 방법을 고려하기보다 데이터베이스를 자신의 모델에 맞게 만드는 방법을 찾기 위해 너무 열심히 노력한다는 것을 알았습니다. 세트 이론. 이로 인해 일반적으로 코드 성능이 저하되는 것을 보았습니다. 또한 성능 조정이 어려운 코드를 생성합니다.

데이터베이스 액세스를 고려할 때 데이터 무결성 (모든 비즈니스 규칙이 사용자 인터페이스를 통하지 않고 데이터베이스 수준에서 적용되어야하는 이유), 성능 및 보안이라는 세 가지 주요 고려 사항이 있습니다. SQL은 프런트 엔드 언어보다 처음 두 가지 고려 사항을 더 효과적으로 관리하도록 작성되었습니다. 이를 위해 특별히 설계 되었기 때문입니다. 데이터베이스의 작업은 사용자 인터페이스의 작업과 훨씬 다릅니다. 작업을 관리하는 데 가장 효과적인 코드 유형이 개념적으로 다르다는 것이 놀라운 일입니까?

그리고 데이터베이스는 기업의 생존에 중요한 정보를 보유하고 있습니다. 기업이 생존이 위태로울 때 새로운 방법을 실험하지 않는 것은 놀라운 일입니다. 도대체 많은 기업이 기존 데이터베이스의 새 버전으로 업그레이드하는 것을 꺼려합니다. 따라서 데이터베이스 설계에는 본질적인 보수주의가 있습니다. 그리고 그것은 의도적으로 그런 식입니다.

T-SQL을 작성하거나 데이터베이스 디자인 개념을 사용하여 사용자 인터페이스를 만들려고하지 않습니다. 왜 인터페이스 언어와 디자인 개념을 사용하여 제 데이터베이스에 액세스하려고합니까? SQL이 충분히 화려하지 않다고 생각하기 때문입니까? 아니면 편하지 않습니까? 당신이 가장 편하게 느끼는 모델에 맞지 않는다고해서 그것이 나쁘거나 잘못되었다는 의미는 아닙니다. 그것은 합법적 인 이유로 다르며 아마도 다를 수 있음을 의미합니다. 다른 작업에 다른 도구를 사용합니다.


"SQL은 어떤 프런트 엔드 언어보다 더 효과적으로 처음 두 가지 고려 사항을 관리하도록 작성되었습니다." 아 그래요? 그렇다면 왜, 그것은 SQL 제약은 여전히 같은 것들을 할 수 없다는 것입니다 ?
Robin Green

그러나 트리거는 복잡한 제약을 처리 할 수있는 트리거의 주요 목적 중 하나입니다.
HLGEM

2
마지막 단락을 앞 단락으로 이동합니다. 다른 사람들도 촉구하는 것을 반영하는 아주 좋은 점입니다. 이것은 다중 패러다임 접근 방식입니다 (일률적 인 접근이 아닙니다).
pestophagous 2010 년

31

Ben Moseley와 Peter Marks의 "Out of the Tar Pit"논문을 참조하십시오. "Out of the Tar Pit"(2006 년 2 월 6 일)

Functional-Relational Programming이라는 프로그래밍 패러다임 / 시스템을 자세히 설명하는 현대 고전입니다. 데이터베이스와 직접적으로 관련되지는 않지만 시스템의 기능적 코어에서 외부 세계 (예 : 데이터베이스)와의 상호 작용을 분리하는 방법에 대해 설명합니다.

이 논문은 또한 관계형 데이터베이스와 관련된 관계형 대수를 사용하여 애플리케이션의 내부 상태가 정의되고 수정되는 시스템을 구현하는 방법에 대해서도 설명합니다.

이 백서에서는 데이터베이스와 함수형 프로그래밍을 통합하는 방법에 대한 정확한 답을 제공하지는 않지만 문제를 최소화하는 시스템을 설계하는 데 도움이 될 것입니다.


4
정말 훌륭한 논문입니다. 귀하가 제공하는 링크가 끊어졌습니다 (일시적으로?). 그러나 shaffner.us/cs/papers/tarpit.pdf
pestophagous

2
@queque 원래 링크는 아직 작동하지 않습니다. Kevin의 답변에 새 링크를 넣었습니다.
David Tonhofer 2014-08-21

25
  1. 기능적 언어는 무국적 상태를 유지하려는 목표가 없으며 상태 관리를 명시 적으로 만드는 목표가 있습니다. 예를 들어, Haskell에서는 State 모나드를 "정상"상태의 핵심으로 간주하고 IO 모나드는 프로그램 외부에 존재해야하는 상태 표현으로 간주 할 수 있습니다. 이 두 모나드는 (a) 상태 저장 작업을 명시 적으로 표현하고 (b) 참조 적으로 투명한 도구를 사용하여 구성함으로써 상태 저장 작업을 구축 할 수 있습니다.

  2. 이름에 따라 데이터베이스를 개체 집합으로 추상화하는 여러 ORM을 참조합니다. 사실 이것은 관계형 데이터베이스의 정보가 나타내는 것이 아닙니다! 이름에 따라 관계형 데이터를 나타냅니다. SQL은 관계형 데이터 세트에 대한 관계를 처리하기위한 대수 (언어)이며 실제로는 그 자체로 상당히 "기능적"입니다. (a) ORM이 데이터베이스 정보를 매핑하는 유일한 방법이 아니라는 점, (b) SQL이 실제로 일부 데이터베이스 디자인에 매우 좋은 언어라는 점, (c) 기능적 언어가 관계형 대수학을 갖는 경우 관용적 (그리고 Haskell의 경우 typechecked) 방식으로 SQL의 힘을 노출하는 매핑.

나는 대부분의 입술이 가난한 사람의 기능적 언어라고 말할 수 있습니다. 현대의 기능 관행에 따라 완전히 사용할 수 있지만 필요하지 않기 때문에 커뮤니티에서 사용할 가능성이 적습니다. 이것은 매우 유용 할 수 있지만 순수한 기능적 인터페이스가 여전히 데이터베이스를 의미있게 사용할 수있는 방법을 확실히 모호하게하는 혼합 된 방법으로 이어집니다.


15

fp 언어의 상태 비 저장 특성이 데이터베이스 연결 문제라고 생각하지 않습니다. Lisp는 순수하지 않은 함수형 프로그래밍 언어이므로 상태를 다루는 데 문제가 없어야합니다. 그리고 Haskell과 같은 순수 함수형 프로그래밍 언어는 데이터베이스 사용에 적용 할 수있는 입력 및 출력을 처리하는 방법을 가지고 있습니다.

귀하의 질문에 따르면 귀하의 주요 문제는 많은 SQL을 작성하지 않고도 데이터베이스에서 가져온 레코드 기반 데이터를 lisp-y (lisp-ish?)로 추상화하는 좋은 방법을 찾는 데 있습니다. 암호. 이것은 언어 패러다임의 문제 라기보다는 도구 / 라이브러리의 문제처럼 보입니다. 순수한 FP를하고 싶다면 lisp가 당신에게 맞는 언어가 아닐 수도 있습니다. Common lisp는 순수한 fp보다는 oo, fp 및 기타 패러다임의 좋은 아이디어를 통합하는 것에 더 가깝습니다. 순수한 FP 경로로 가고 싶다면 Erlang이나 Haskell을 사용해야 할 것입니다.

나는 lisp의 'pseudo-oo'아이디어에도 장점이 있다고 생각합니다. 시도해 볼 수 있습니다. 데이터로 작업하려는 방식에 맞지 않는 경우 Weblocks 위에 원하는 방식으로 데이터를 작업 할 수있는 레이어를 만들 수 있습니다. 이것은 모든 것을 직접 작성하는 것보다 쉬울 수 있습니다.

면책 조항 : 저는 Lisp 전문가가 아닙니다. 저는 주로 프로그래밍 언어에 관심이 있고 Lisp / CLOS, Scheme, Erlang, Python 및 약간의 Ruby를 가지고 놀았습니다. 일상적인 프로그래밍 생활에서 저는 여전히 C #을 사용해야합니다.


3
Erlang은 단어의 어떤 정의로도 순수한 FP가 아닙니다. 예를 들어 smalltalk의 객체처럼 서로에게 메시지를 보내는 많은 프로세스 (모두 병렬로 실행 됨)를 생성하여 erlang을 작성합니다. 따라서 높은 수준의 관점에서 보면 다소 OO처럼 보일 수도 있고 확실히 상태가 있습니다. 확대하면 (프로세스 내에서 실행되는 코드로) 더 기능적으로 보이지만 여전히 순수하게 작동하지는 않습니다. 원하는 곳에서 메시지를 보내고 (따라서 I / O 등을 수행 할 수 있음) "저장할뿐만 아니라" 전역 변수 "("프로세스 사전 "이라고하는 내부 프로세스에 전역)
Amadiro

@Amadiro "확실히 상태가 있습니다". 물론 그렇습니다. 우리는 항상 상태를 가지고 있습니다. 문제는 상태가 아니라 변경 가능한 상태 입니다. "기능적 프로그래밍"의 좋은 부분은 깨지기 쉬운 상태 표현을 제거하는 것입니다 (예 : 부상에 대한 모욕을 추가하기 위해 트랜잭션이 아닌 방식으로 참조를 유지하는 동안 다른 프로세스에 의해 변경되는 객체 인스턴스). Erlang은 변경 불가능한 상태를 가지고 있으므로이 함수형 프로그래밍 기준에 부합합니다. 따라서 어떤 종류의 데이터베이스도 문제가되지 않습니다. 데이터베이스 업데이트 가 문제입니다 ( Prolog 의 불쾌한 주장 도 참조 ).
David Tonhofer 2014-08-21

15

데이터베이스가 정보를 파괴하지 않는 경우 전체 데이터베이스의 기능을 값으로 사용하여 "순수 기능"프로그래밍 값과 일치하는 기능적 방식으로 정보를 사용할 수 있습니다.

T 시간에 데이터베이스에 "Bob이 Suzie를 좋아한다"라고 표시되고 데이터베이스와 liker를 수락하는 기능이 있으면 T 시간에 데이터베이스를 복구 할 수있는 한 데이터베이스를 포함하는 순수한 기능 프로그램을 갖게됩니다. . 예 :

# Start: Time T
likes(db, "Bob")
=> "Suzie"
# Change who bob likes
...
likes(db "Bob")
=> "Alice"
# Recover the database from T
db = getDb(T)
likes(db, "Bob")
=> "Suzie"

이를 위해 사용할 수있는 정보를 버릴 수 없으므로 (실용적으로 정보를 버릴 수 없음) 스토리지 요구 사항이 단조롭게 증가합니다. 그러나 후속 값이 트랜잭션을 통해 이전 값과 관련되는 일련의 이산 값으로 데이터베이스 작업을 시작할 수 있습니다.

예를 들어 이것은 Datomic 이면의 주요 아이디어 입니다.


좋은. Datomic에 대해서도 몰랐습니다. 참조 : Datomic의 근거 .
David Tonhofer 2014-08-21

12

전혀. '기능 데이터베이스'라는 장르의 데이터베이스가 있으며, 그중 Mnesia 가 아마도 가장 접근하기 쉬운 예일 것입니다. 기본 원칙은 함수형 프로그래밍이 선언적이므로 최적화 할 수 있다는 것입니다. 영구 컬렉션에서 List Comprehensions 를 사용하여 조인을 구현할 수 있으며 쿼리 최적화 프로그램은 디스크 액세스를 구현하는 방법을 자동으로 해결할 수 있습니다.

Mnesia는 Erlang 으로 작성되었으며 해당 플랫폼에 사용할 수있는 웹 프레임 워크 ( Erlyweb )가 하나 이상 있습니다. Erlang은 본질적으로 비공유 스레딩 모델과 병렬이므로 특정 방식으로 확장 가능한 아키텍처에 적합합니다.


1
나는 그것이 많은 해결책이라고 생각하지 않습니다. 객체 지향 데이터베이스도 있지만 일반적으로 일반 오래된 관계형 SQL 데이터베이스에 연결하려고합니다.
jalf

4
함수 SQL 임피던스 불일치가있는 것과 거의 동일한 방식으로 OO 언어 및 데이터베이스와 임피던스 불일치가 있습니다.
ConcernedOfTunbridgeWells

1
@ConcernedOfTunbridgeWells 나는이 임피던스 불일치가 모든 것이 못될 필요가있는 망치를 가진 사람들의 상상력의 산물이라고 임의로 말할 것입니다. SQL에 대한 매우 얇은 레이어와 지식은 우아하게 먼 길을 갈 수 있으므로 jOOQ 및 유사한 shim이 있습니다.
David Tonhofer 2014 년

6

데이터베이스는 상태 비 저장 API에서 상태를 추적하는 완벽한 방법입니다. REST를 구독하는 경우 목표는 클라이언트가 할 필요가 없도록 투명한 방식으로 상태 정보를 추적하는 데이터 저장소 (또는 다른 백엔드)와 상호 작용하는 상태 비 저장 코드를 작성하는 것입니다.

데이터베이스 레코드를 객체로 가져온 다음 수정하는 객체 관계형 매퍼의 개념은 객체 지향 프로그래밍과 마찬가지로 함수형 프로그래밍에도 적용 가능하고 유용합니다. 한 가지주의 할 점은 함수형 프로그래밍이 객체 를 제자리에서 수정하지는 않지만 데이터베이스 API를 사용하면 레코드 를 제자리에서 수정할 수 있다는 것 입니다. 클라이언트의 제어 흐름은 다음과 같습니다.

  • 레코드를 개체로 가져옵니다 (데이터베이스 API는이 시점에서 레코드를 잠글 수 있음).
  • 원하는대로 내용을 기반으로 개체와 분기를 읽습니다.
  • 원하는 수정 사항으로 새 개체를 패키징하고,
  • 데이터베이스의 레코드를 업데이트하는 적절한 API 호출에 새 개체를 전달합니다.

데이터베이스는 변경 사항으로 레코드를 업데이트합니다. 순수 함수형 프로그래밍은 프로그램 범위 내에서 변수 재 할당을 허용하지 않을 수 있지만 데이터베이스 API는 여전히 내부 업데이트를 허용 할 수 있습니다.


5

저는 Haskell이 가장 편합니다. 가장 유명한 Haskell 웹 프레임 워크 (Rails 및 Django와 비교할 수 있음)는 Yesod입니다. 꽤 멋지고 형식이 안전한 다중 백엔드 ORM이있는 것 같습니다. 그들의 책에서 Persistance 장 을 살펴보십시오 .


0

데이터베이스와 함수형 프로그래밍은 융합 될 수 있습니다.

예를 들면 :

Clojure는 관계형 데이터베이스 이론에 기반한 함수형 프로그래밍 언어입니다.

               Clojure -> DBMS, Super Foxpro
                   STM -> TransactionMVCC
Persistent Collections -> db, table, col
              hash-map -> indexed data
                 Watch -> trigger, log
                  Spec -> constraint
              Core API -> SQL, Built-in function
              function -> Stored Procedure
             Meta Data -> System Table

참고 : 최신 spec2에서 spec은 RMDB와 비슷합니다. 참조 : spec-alpha2 위키 : 스키마 및 선택

나는 옹호한다 : NoSQL과 RMDB 이점의 조합을 달성하기 위해 해시 맵 위에 관계형 데이터 모델을 구축한다. 이것은 실제로 posgtresql의 역 구현입니다.

오리 타이핑 : 오리처럼 보이고 오리처럼 꽥꽥 거리는 경우 오리 여야합니다.

RMDB와 같은 clojure의 데이터 모델, RMDB와 같은 clojure의 시설 및 RMDB와 같은 clojure의 데이터 조작이라면 clojure는 RMDB 여야합니다.

Clojure는 관계형 데이터베이스 이론에 기반한 함수형 프로그래밍 언어입니다.

모든 것이 RMDB입니다.

해시 맵 (NoSQL)을 기반으로 관계형 데이터 모델 및 프로그래밍 구현

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.