문제

하나님이 싫어하는 용어"코드 냄새"하지만 나는 아무것도 생각할 수 없다 더 정확합니다.

나는 디자인은 높은 수준의 언어와 컴파일러가 에서 여유를 배울 시간에 대한 컴파일러 건설,언어 디자인,프로그래밍 기능(컴파일러를 쓰고 있는용).

안 코드 생성은 단계의 컴파일러,난을 유지하"상태"틱 데이터로 통합 구문을 나무입니다.예를 들어,컴파일하는 경우 흐름 제어문가 필요성에 대해 고유 이름의 라벨을 뛰어(레이블에서 생성되는 카운터는 전달에서,업데이트&반환되고 오래된 카운터 값을 해야 되지 않은 다시 사용).또 다른 예는 때에 걸쳐 온-라인에서 문자열 리터럴 구문,나무들이 영구적으로 변환로 힙 변수(에 공백 문자열은 최고의에 저장된 힙).나는 현재 포장 전체 코드 생성에서 모듈의 상태로 설계되었습니다.

었다는 말을 쓰는 컴파일러는 잘 문제에 적합한 기능적인 패러다임을,그러나 내가 찾는 나는 디자인이 동일한 방법으로 나는 그것을 디자인에서는 C(당신이 정말로 쓸 수 있는 C 언어-심지어는 메인/w 상태를 사용해).

고 싶은 생각하는 방법을 알아에서켈(오히려 기능적 패러다임)-지 않 C 켈문입니다.나는 정말을 제거하려고/의 사용을 최소화 상태되었거나,그것은 합법적인 기능적인"디자인 패턴을"?

도움이 되었습니까?

해결책

내가 말하는 국가에서 일반하지 않는 냄새가 코드,그래서 그것은 작은 유지하고 잘 통제됩니다.

이를 사용해와 같은 상태,세인트 또는 맞춤형 것,또는 데이터 구조를 포함하는 국가는 데이터는 당신이 주위에 전달하는 몇 가지 장소가 나쁜 일이 아닙니다.(사실을 사용해 단원에서는 정확하게 하고 있다!) 그러나,국가는 모든 장소에(예,이것은 당신이,IO 사!) 나쁜 냄새가 있다.

는 상당히 취소 예었을 때 팀에서 일하는 우리의 입장에 대한 ICFP 프로그래밍 Contest2009 (코드에서 사용할 수 있 git://할 수 있습니다..냉소.net/일/icfp-contest-2009).결국 우리와 함께 몇 가지 다른 모듈 부품을 this:

  • VM:가상 컴퓨터가 실행 시뮬레이션 프로그램
  • 컨트롤러:여러 세트의 일과는 읽기의 출력을 시뮬레이터를 생성된 새로운 제어 입력
  • 솔루션:세대의 솔루션에 따라 파일의 출력을 컨트롤러
  • 옵션:여러 세트의 일과는 모두 읽을 입력 및 출력 포트 및 생성된 어떤 종류의 시각화하거나 로그에 무슨 일이 있었으로 시뮬레이션 진행

이것들은 각각 자신의 상태,그리고 그들은 모든 상호 작용에서 다양한 방법을 통해 입력과 출력 값의 VM.우리는 여러 가지 서로 다른 컨트롤러 및 시각화하는 각각의 그것의 자신의 다른 종류의 상태에 있습니다.

여기에서 중요한 점이었다는 내부의 어떤 특별한 상태에 제한되었을 자신의 특정 모듈이고,각 모듈에 대해 아무것도 알지도 존재의 상태에 대한 다른 모듈을 사용합니다.어떤 특별한 설정의 상태 코드 및 데이터는 일반적으로 몇 다스 라인,오래 한줌의 데이터 항목에서는 상태입니다.

는 모든이 함께 붙어에서 하나의 작은의 기능에 대한 다스 라인하는 액세스 할 수 없었을 내부의 모든 상태는 단순하게라고 올바른 일을 올바른 순서로 반복 시뮬레이션을 통해 전달되고 매우 제한된 양의 외부에 정보를 각 모듈(와 함께 모듈의 상태,of course).

면 상태에서 사용된 같은 제한적인 방법과 유형을 시스템에서 당신을 방해하는 실수로 그것을 수정하여,그것은 확실히 처리하기 쉽습니다.그것은 아름다움 중 하나는 여러는 그것을 할 수 있습니다.

하나 대답을 말한다,"사용하지 않을 사용해." 나의 관점에서,이것은 정확히 뒤에 있다.을 사용해은 제어 구조는 다른 것들 사이에,당신을 도울 수 있습량을 최소화하는 코드는 상태입니다.에서 보면 monadic 파서 예를 들어,상태 분석(즉,텍스트 분석되는,얼마나 하나가에 그것은,모든 경고 있는 축적,etc.) 실행해야를 통해 모든 연결에 사용되는 parser.아직 하실 것입니다 몇 가지가 연결되는 실제로 조작 상태로 직접;다른 것 중 하나를 사용하여 이러한 몇 가지 기능이 있다.이것은 명확하고 한 장소에서 모두의 작은 금액이드 상태를 변경할 수 있는 보다 쉽게 이해할 수 있는 방법을 변경,다시 보다 쉽게 처리합니다.

다른 팁

Haskell에 여러 컴파일러를 작성했으며 State Monad는 많은 컴파일러 문제에 대한 합리적인 솔루션입니다. 그러나 당신은 그것을 추상적으로 유지하고 싶습니다 --- 당신이 모나드를 사용하고 있음을 분명하게 만들지 마십시오.

Glasgow Haskell Compiler의 예는 다음과 같습니다 (내가 한 ~ 아니다 쓰다; 제어 흐름 그래프를 제작하는 몇 개의 가장자리를 둘러싼 다). 그래프를 만드는 기본 방법은 다음과 같습니다.

empyGraph    :: Graph
mkLabel      :: Label -> Graph
mkAssignment :: Assignment -> Graph  -- modify a register or memory
mkTransfer   :: ControlTransfer -> Graph   -- any control transfer
(<*>)        :: Graph -> Graph -> Graph

그러나 발견 한대로 고유 한 레이블의 공급을 유지하는 것은 기껏해야 지루하기 때문에 이러한 기능도 제공합니다.

withFreshLabel :: (Label -> Graph) -> Graph
mkIfThenElse :: (Label -> Label -> Graph) -- branch condition
             -> Graph   -- code in the 'then' branch
             -> Graph   -- code in the 'else' branch 
             -> Graph   -- resulting if-then-else construct

전체 Graph 물건은 추상 유형이며, 번역가는 Monadic이 진행되고 있음을 알지 못하고 순수한 기능적 방식으로 그래프를 완벽하게 구성합니다. 그런 다음 그래프가 마지막으로 구성되면 코드를 생성 할 수있는 대수 데이터 유형으로 전환하기 위해 고유 한 레이블을 공급하고 State Monad를 실행하며 데이터 구조를 가져옵니다.

주 모나드는 아래에 숨겨져 있습니다. 클라이언트에 노출되지는 않지만 Graph 다음과 같습니다.

type Graph = RealGraph -> [Label] -> (RealGraph, [Label])

또는 좀 더 정확하게

type Graph = RealGraph -> State [Label] RealGraph
  -- a Graph is a monadic function from a successor RealGraph to a new RealGraph

State Monad가 추상화 층 뒤에 숨겨져 있으면 전혀 냄새가 나지 않습니다!

당신은 보셨습니까? 속성 문법 (Ag)? (자세한 정보 위키 백과 그리고 기사 Monad Reader에서)?

AG를 사용하면 추가 할 수 있습니다 속성 구문 트리에. 이러한 속성은 분리되어 있습니다 합성 그리고 상속 속성.

합성 된 속성은 구문 트리에서 생성 (또는 합성), 이것은 생성 된 코드 또는 모든 주석 또는 관심있는 모든 것이 될 수 있습니다.

상속 된 속성은 구문 트리에 입력되며, 이는 환경 또는 코드 생성 중에 사용할 레이블 목록 일 수 있습니다.

Utrecht University에서 우리는 다음을 사용합니다 속성 문법 시스템 (uuagc) 컴파일러를 작성합니다. Haskell 코드를 생성하는 사전 프로세서입니다..hs 제공된 파일) .ag 파일.


비록 당신이 여전히 Haskell을 배우고 있다면, 아마도 아마도 그에 대한 또 다른 추상화 계층을 배우기 시작할 때가 아닙니다.

이 경우 문법이 생성하는 속성의 종류를 수동으로 쓸 수 있습니다.

data AbstractSyntax = Literal Int | Block AbstractSyntax
                    | Comment String AbstractSyntax

compile :: AbstractSyntax -> [Label] -> (Code, Comments)
compile (Literal x) _      = (generateCode x, [])
compile (Block ast) (l:ls) = let (code', comments) = compile ast ls
                             in (labelCode l code', comments)
compile (Comment s ast) ls = let (code, comments') = compile ast ls
                             in (code, s : comments')

generateCode :: Int -> Code
labelCode :: Label -> Code -> Code

모나드 대신 적용 기능을 원할 수 있습니다.

http://www.haskell.org/haskellwiki/applicative_functor

그러나 원래 논문은 위키보다 더 잘 설명한다고 생각합니다.

http://www.soi.city.ac.uk/~ross/papers/applicative.html

나는 State Monad를 사용하는 것이 상태를 모델링하는 데 익숙 할 때 코드 냄새라고 생각하지 않습니다.

함수를 통해 상태를 실행 해야하는 경우 상태를 명시 적으로 수행하여 상태를 인수로 취하고 각 기능에서 반환 할 수 있습니다. State Monad는 좋은 추상화를 제공합니다. 국가를 통과하고 상태가 필요한 기능을 결합하는 유용한 기능을 많이 제공합니다. 이 경우 State Monad (또는 응용 프로그램)를 사용하는 것은 코드 냄새가 아닙니다.

그러나 State Monad를 사용하여 필수 프로그램 스타일의 프로그래밍을 모방하는 경우 기능 솔루션으로 충분할 것입니다.

일반적으로 가능한 한 상태를 피하려고 노력해야하지만 항상 실용적인 것은 아닙니다. Applicative 효과적인 코드를 더 멋지게 보이고 기능적으로 보이게 만듭니다. 특히 트리 트래버스 코드는이 스타일의 혜택을 누릴 수 있습니다. 이름 생성 문제를 위해서는 이제 다소 좋은 패키지가 있습니다. 가치 공급.

글쎄, 모나드를 사용하지 마십시오. 기능 프로그래밍의 힘은 기능 순도와 재사용입니다. 내 교수가 한 번 쓴이 논문이 있으며 그는 Haskell을 짓는 데 도움을 준 사람들 중 하나입니다.

논문은 "기능 프로그래밍이 중요한 이유", 나는 당신이 그것을 읽는 것이 좋습니다. 좋은 읽기입니다.

용어에 대해 조심해 보겠습니다. 상태는 그 자체로 나쁘지 않습니다. 기능적 언어에는 상태가 있습니다. "코드 냄새"는 변수 값을 할당하고 변경하고 싶을 때입니다.

물론, Haskell State Monad는 그 이유가 있습니다. I/O와 마찬가지로 제한된 맥락에서 안전하지 않고 작동하지 않는 일을 할 수 있습니다.

그렇습니다. 아마도 코드 냄새 일 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top