2011-12-20 5 views
27

이것은 약간 흐릿해질 수 있지만, 잠시 동안 궁금해하고 있습니다. ! 내 알기로, 하나는 값이 구성되기 전에 데이터 생성자에 대한 확인 매개 변수가 평가되고 만들 수 있습니다데이터 유형의 엄격한 필드의 장점

data Foo = Bar !Int !Float 

나는 종종 게으름이 대단한 일이라고 생각했다. 이제 출처를 살펴볼 때 ! -less 변형보다 엄격한 입력란이 더 자주 나타납니다.

이 기능의 장점은 무엇이며 왜 그대로 두지 않아야합니까?

답변

32

Int 및 Float 필드에 큰 계산을 저장하지 않는 한, 상당한 오버 헤드가 썽크로 가득한 많은 사소한 계산에서 축적 될 수 있습니다. 예를 들어, 데이터 유형의 lazy Float 필드에 1을 반복적으로 추가하면 실제로 필드를 강제 계산하여 계산할 때까지 더 많은 메모리를 사용합니다.

종종 필드에서 값 비싼 계산에 저장하려고합니다. 그러나 사전에 그런 일을하지 않을 것이라는 것을 알게되면 필드를 엄격하게 표시하고 수동으로 seq을 추가하지 않아도 원하는 효율성을 얻을 수 있습니다. 플래그를 지정하면 추가 보너스로

-funbox-strict-fields GHC 직접 그들이 항상 평가 될 것입니다 알고 있기 때문에 가능한 데이터 형식 자체에 엄격한 필드 데이터 유형의 1 압축을 풀 것이며, 따라서 더 썽크에 없습니다 할당된다. 이 경우 막대 값은 데이터를 포함하는 썽크에 대한 두 개의 포인터를 포함하지 않고 메모리의 막대 값 바로 안에있는 Int 및 Float을 구성하는 기계 단어를 포함합니다.

게으름은 매우 유용하지만 일부는 시간이 흐르면서 계산을 방해합니다. 특히 작은 필드는 항상보고 (따라서 강제로) 또는 자주 수정되지만 매우 비싼 계산. 엄격한 필드는 데이터 유형의 모든 용도를 수정할 필요없이 이러한 문제를 해결하는 데 도움이됩니다.

게으른 필드보다 일반적인지 여부는 읽는 코드의 유형에 따라 다릅니다. 예를 들어, 게으르다는 이점 때문에 기능적 트리 구조가 엄격한 필드를 광범위하게 사용하는 것을 볼 가능성이 없습니다.

의 당신이 중위 작업의 생성자를 가진 AST 있다고 가정 해 봅시다 :

data Exp = Infix Op Exp Exp 
     | ... 

data Op = Add | Subtract | Multiply | Divide 

당신은 그 전체 AST 평가되는 것을 의미 할 것 같은 정책을 적용하는 한, Exp 필드를 엄격하게하고 싶지 않아요을 당신이 게으름으로부터 이익을 얻고 자하는 것이 아닌, 최상위 노드를 볼 때마다. 그러나 Op 필드에는 나중에 계산할 값 비싼 계산이 포함되지 않으므로 깊숙이 중첩 된 구문 분석 트리가 있으면 중개 연산자 당 썽크의 오버 헤드가 높아질 수 있습니다. 따라서 중위 생성자의 경우 Op 필드를 엄격하게 설정하고 두 개의 Exp 필드는 그대로 두는 것이 좋습니다.

단일 생성자 유형 만 압축을 풀 수 있습니다.

+1

마찬가지로 AST는 엄격하지 않아야합니까? – Lanbo

+0

예를 들어 대서양 표준시를 사용하여 정교화하여 답변을 확장했습니다. – ehird

4

지연과 관련된 오버 헤드가 있습니다. 컴파일러는 결과가 필요할 때까지 계산을 저장하는 값에 대한 썽크를 만들어야합니다. 조만간 결과가 필요할 것이라는 것을 알게되면 결과 평가를 강제 할 수 있습니다.

4

게으름이 발생합니다. 그렇지 않으면 모든 언어에서 비용이 발생합니다.

비용은 두 배입니다 : 그것은 썽크를 설정하는 데 시간이 오래 걸릴 수 있습니다

  1. (즉, 결국 계산하려고 할 때 계산하는 무슨의 설명) 작업을 수행하는 것보다 곧.
  2. 다른 썽크에 엄격하지 않은 인수로 들어가는 평가되지 않은 썽크는 다른 썽크 등에 엄격하지 않은 인수로 사용되어 점점 더 많은 메모리를 사용합니다. 불행하게도, 그 튜크는 더 이상 액세스 할 수없는 메모리, 즉 썽크 만 평가 될 때 해제 될 수있는 메모리에 대한 참조를 보유 할 수있어 가비지 컬렉터가 작업을 수행하지 못하게합니다. 예를 들어, 트리의 특정 값을 업데이트하기로되어있는 썽크가 있습니다. 이 값이 100MB 상당의 다른 값을 보유한다고 가정 해보십시오. 더 이상 오래된 트리에 대한 참조가 없으면이 메모리는 썽크가 평가되지 않는 한 낭비됩니다.
  3. 다른 답변에서 제공하는 정보 외에도
5

, 명심 :

을 제가 알기로 !로, 하나는 반드시 데이터 생성자의 매개 변수가 평가되고 만들 수있는 가치가 구축되기 전에 이 WHNF로 평가 seq$!과 같다 -

이 방법 deep the parameter is evaluated보고 흥미 롭군요.

데이터 유형

data Foo = IntFoo !Int | FooFoo !Foo | BarFoo !Bar 
data Bar = IntBar Int 

let x' = IntFoo $ 1 + 2 + 3 
in x' 

가 WHNF 식에 따라 평가 값을 IntFoo 6 (== 완전히 평가, NF를 ==) 만들어 주어.
또한,이 식을 평가 WHNF
let x' = FooFoo $ IntFoo $ 1 + 2 + 3 
in x' 

값을 FooFoo (IntFoo 6) (== 완전히 평가, NF를 ==) 생성한다. 그러나
, WHNF로 계산이 식
let x' = BarFoo $ IntBar $ 1 + 2 + 3 
in x' 

BarFoo (IntBar (1 + 2 + 3)) 값을 생성한다 (! = 완전히 평가! = NF).

홈페이지 포인트 : Bar의 데이터 생성자는 엄격한 매개 변수 자체를 포함하지 않는 경우!Bar 매개 변수의 엄격함이 반드시 도움이되지 않습니다.

+0

매우 명확한 예! ghci 또는 다른 도구에서 매개 변수가 얼마나 깊이 평가되는지 확인할 수 있습니까? – wenlong

+1

@wenlong [썽크를 시각화 할 때의 SO 응답] (http://stackoverflow.com/questions/16767028/anyway-to-visualize-a-thunk-function-or-how-to-view-a-function -for-a-general), 특히 도구 ['ghc-vis'] (http://felsin9.de/nnis/ghc-vis/#basic-usage) – mucaho