Haskell Language
엄밀
수색…
강타 패턴
강타 ( !
)로 주석이 달린 패턴은 느리게 대신 엄격하게 평가됩니다.
foo (!x, y) !z = [x, y, z]
이 예제에서 x
와 z
는 모두 목록을 반환하기 전에 weak head normal form으로 평가됩니다. 그것은 다음과 같습니다 :
foo (x, y) z = x `seq` z `seq` [x, y, z]
Bang 패턴은 Haskell 2010 BangPatterns
언어 확장을 사용하여 활성화됩니다.
일반 양식
이 예제는 간단한 개요를 제공합니다. 일반적인 양식 과 예제에 대한 자세한 설명은 이 질문을 참조하십시오.
감소 된 정상형
표현식의 감소 된 정상형 (또는 정상적인 형태, 문맥이 명확 할 때)은 주어진 표현식에서 모든 축소 가능한 부분 표현식을 평가 한 결과입니다. 하스켈의 비 엄격한 의미론 (일반적으로 게으름 이라고 함)으로 인해 바인더 아래에있는 경우 하위 표현식을 줄일 수 없습니다 (예 : 람다 추상화 - \x -> ..
). 표현식의 정규형은 존재하는 경우 고유 한 특성을 갖습니다.
즉, 하위 표현식을 줄이는 순서 (의미 적 의미론의 측면에서)는 중요하지 않습니다. 그러나 퍼포먼스 하스켈 프로그램을 작성하는 열쇠는 올바른 표현이 적시에 평가되는 것을 보장하는 것, 즉 운영 의미론을 이해하는 것입니다.
그 정규형 식은 자체는 정상 형태로 알려져있다.
일부 표현식 (예 : let x = 1:x in x
)은 정규 양식이 없지만 여전히 생산적입니다. 무제한 값을 허용하는 경우 예제 식은 여전히 값을 가지며 여기에는 [1,1, ...]
목록이 있습니다. let y = 1+y in y
와 같은 다른 표현식에는 값이 없거나 그 값은 undefined
.
약한 머리 정상형
RNF는 표현식을 완전히 평가하는 것과 같습니다. 마찬가지로 약한 머리 정규형 (WHNF)은 표현의 머리 를 평가하는 것과 같습니다. 표현식 e
의 머리 부분은 e
가 응용 프로그램 일 경우 완전히 평가됩니다 Con e1 e2 .. en
과 Con
은 생성자입니다. 또는 추상화 \x -> e1
; 또는 부분적인 어플리케이션 f e1 e2 .. en
, 부분적인 어플리케이션 f
가 n
개 이상의 인수를 취하는 것을 의미합니다 (또는 등가 적으로, e
의 타입은 함수 타입입니다). 어쨌든, 부분 식 e1..en
은 e1..en
에있는 식에 대해 평가되거나 평가되지 않을 수 있습니다. 심지어 undefined
않을 수도 있습니다.
Haskell의 평가 의미는 WHNF로 표현 될 수있다. - 표현식 e
를 평가하고, 먼저 WHNF로 평가 한 다음, 모든 하위 표현식을 왼쪽에서 오른쪽으로 재귀 적으로 평가한다.
원시 seq
함수는 표현식을 WHNF로 평가하는 데 사용됩니다. seq xy
는 표기법 상 y
같습니다 ( seq xy
의 값은 정확하게 y
). 또한 y
가 WHNF로 평가 될 때 x
는 WHNF로 평가됩니다. 식은 다음과 같이 구문이있는 -XBangPatterns
확장명으로 활성화 된 bang 패턴을 사용하여 WHNF로 평가할 수도 있습니다.
f !x y = ...
여기서 f
는 평가 될 때 x
가 WHNF로 평가되고 y
는 (필연적으로) 평가되지 않습니다. 강타 패턴은 생성자에 나타날 수도 있습니다.
data X = Con A !B C .. N
이 경우 생성자 Con
은 B
필드에서 엄격한 것으로, 이는 생성자가 충분한 (여기, 2 개의) 인수에 적용될 때 B
필드가 WHNF로 평가된다는 것을 의미합니다.
게으른 패턴
게으른 또는 반박 할 수없는 패턴 ( ~pat
구문으로 표시)은 일치하는 값을 보지 않고도 항상 일치하는 패턴입니다. 즉, 게으른 패턴은 하단 값과 일치합니다. 그러나 반박 불가능한 패턴의 하위 패턴에 바인드 된 변수를 계속 사용하면 일치가 발생하지 않는 한 아래쪽으로 평가되는 패턴 일치가 강제 실행됩니다.
다음 함수는 인수에서 느슨합니다.
f1 :: Either e Int -> Int
f1 ~(Right 1) = 42
그래서 우리는
λ» f1 (Right 1)
42
λ» f1 (Right 2)
42
λ» f1 (Left "foo")
42
λ» f1 (error "oops!")
42
λ» f1 "oops!"
*** type mismatch ***
다음 함수는 게으른 패턴으로 작성되었지만 실제로 일치를 강제하는 패턴의 변수를 사용하기 때문에 Left
인수에서 실패합니다.
f2 :: Either e Int -> Int
f2 ~(Right x) = x + 1
λ» f2 (Right 1)
2
λ» f2 (Right 2)
3
λ» f2 (Right (error "oops!"))
*** Exception: oops!
λ» f2 (Left "foo")
*** Exception: lazypat.hs:5:1-21: Irrefutable pattern failed for pattern (Right x)
λ» f2 (error "oops!")
*** Exception: oops!
let
바인딩, 같은 반박 할 수없는 패턴을 게으른 행동하고 있습니다 :
act1 :: IO ()
act1 = do
ss <- readLn
let [s1, s2] = ss :: [String]
putStrLn "Done"
act2 :: IO ()
act2 = do
ss <- readLn
let [s1, s2] = ss
putStrLn s1
여기서 act1
은 모든 문자열 목록을 구문 분석하는 입력에 대해 작동하지만, act2
에서는 putStrLn s1
이 [s1, s2]
대해 패턴 일치를 강제하는 s1
값을 필요로하기 때문에 정확히 두 문자열 목록에서만 작동합니다.
λ» act1
> ["foo"]
Done
λ» act2
> ["foo"]
*** readIO: no parse ***
엄격한 필드
data
선언에서 유형 앞에 접두사 ( !
)를 붙이면 필드가 엄격한 필드가 됩니다. 데이터 생성자가 적용되면 해당 필드는 약한 머리 일반 양식으로 평가되므로 필드의 데이터는 항상 약한 머리 일반 양식으로 보장됩니다.
엄격한 필드는 레코드 및 비 레코드 유형 모두에서 사용할 수 있습니다.
data User = User
{ identifier :: !Int
, firstName :: !Text
, lastName :: !Text
}
data T = MkT !Int !Int