엄격한 컨텍스트에서 Haskell의 존재 유형 ( http://www.haskell.org/haskellwiki/Existential_type ) 을 사용하고 싶습니다 . 저는 haskell-wiki에서 예제를 가져 와서 엄격한 이기종지도를 만들려고했습니다. 지도와 그 값이 완전히 평가되어야합니다.
이것을 테스트하기 위해 세 가지 유형을 정의했습니다. 첫 번째는 단순한 엄격한지도입니다. 두 번째 유형은 실존 유형을 사용하는 이기종 맵입니다. 세 번째 유형은 두 번째 유형과 비슷하지만 NFData 제약 조건을 추가합니다.
첫 번째 간단한 예제는 진정으로 엄격하고 완전히 평가되지만 다른 예제는 그렇지 않습니다. deepseq를 사용하는 세 번째 유형조차도 완전히 평가되지 않은 것 같습니다.
내 질문은 다음과 같습니다.
예제 소스
{-# LANGUAGE ExistentialQuantification #-}
import GHC.AssertNF
import Control.DeepSeq
import Data.Map.Strict
-- 1) simple container
data Obj a = Obj a
-- using a smart constructor here to ensure arbitrary values are strict
mkObj :: a -> Obj a
mkObj a = Obj $! a
-- using a special String constructor to ensure Strings are always
-- fully evaluated in this example
mkString :: String -> String
mkString x = force x
xs :: Map Int (Obj String)
xs = fromList [ (1, mkObj . mkString $ "abc")
, (2, mkObj . mkString $ "def")
, (3, mkObj . mkString $ "hij")
]
-- 2) container using existential quantification
data Obj2 = forall a. (Show a) => Obj2 a
-- using the smart constructor here has no effect on strictness
mkObj2 :: Show a => a -> Obj2
mkObj2 a = Obj2 $! a
xs2 :: Map Int Obj2
xs2 = fromList [ (1, mkObj2 1)
, (2, mkObj2 . mkString $ "test")
, (3, mkObj2 'c')
]
-- 3) container using existential quantification and deepseq
data Obj3 = forall a. (NFData a, Show a) => Obj3 !a
instance NFData Obj3 where
-- use default implementation
mkObj3 :: (NFData a, Show a) => a -> Obj3
mkObj3 a = Obj3 $!! a
xs3 :: Map Int Obj3
xs3 = fromList [ (1, mkObj3 (1::Int))
, (2, mkObj3 . mkString $ "abc")
, (3, mkObj3 ('c'::Char))
]
-- strictness tests
main :: IO ()
main = do
putStr "test: simple container: "
(isNF $! xs) >>= putStrLn . show
assertNF $! xs
putStr "test: heterogeneous container: "
(isNF $! xs2) >>= putStrLn . show
assertNF $! xs2
putStr "test: heterogeneous container with NFData: "
(isNF $!! xs3) >>= putStrLn . show
assertNF $!! xs3
return ()
GHCI 출력
test: simple container: True
test: heterogeneous container: False
Parameter not in normal form: 1 thunks found:
let x1 = Tip()
in Bin (I# 2) (Obj2 (_sel (_bh (...,...))) (C# 't' : C# 'e' : ... : ...)) (Bin (I# 1) (Obj2 (D:Show _fun _fun _fun) (S# 1)) x1 x1 1) (Bin (I# 3) (Obj2 (D:Show _fun _fun _fun) (C# 'c')) x1 x1 1) 3
test: heterogeneous container with NFData: False
Parameter not in normal form: 1 thunks found:
let x1 = _ind ...
x2 = Tip()
in _bh (Bin (I# 2) (Obj3 (_bh (_fun x1)) (_sel (_bh (...,...))) (C# 'a' : C# 'b' : ... : ...)) (Bin (I# 1) (Obj3 (_ind _fun) (D:Show _fun _fun _fun) (I# 1)) x2 x2 1) (Bin (I# 3) (Obj3 x1 (D:Show _fun _fun _fun) (C# 'c')) x2 x2 1) 3)
믿거 나 말거나, 세 가지 테스트 모두 엄격합니다! 의미에서 저장하는 "이종 객체"는 컨테이너 객체에 넣기 전에 평가됩니다.
엄격하지 않은 것은 실존 적 구현 일뿐입니다. 문제는 Haskell이 실제로 실존성을 가지고 있지 않으며 유형 클래스 사전을 저장하는 레코드 유형에 의해 에뮬레이션된다는 것입니다. Show
제약 조건의 경우 기본적으로 객체를 저장하지 않고 show
문자열 인의 결과 만 저장한다는 의미 입니다. 그러나 GHC는 그 문자열이 엄격하게 평가 되기를 바라는 것을 알 수 없습니다 . 사실 그것은 show
일반적으로 객체를 심층 평가하는 것보다 훨씬 더 비쌀 수 있기 때문에 일반적으로 나쁜 생각 입니다. 그래서 show
당신이 그것을 부를 때 평가 되어야만합니다. 이것은 아주 좋은 IMO입니다.
show
엄격하게 평가하려는 경우 확인하는 유일한 방법은 레코드 변환을 명시 적으로 만드는 것입니다. 귀하의 예에서는 사소한 것입니다.
newtype Obj2 = Obj2 { showObj2 :: String }
mkObj2 :: Show a => a -> Obj2
mkObj2 = (Obj2 $!) . show
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다