我想T f()使用 QuickCheck 作為外部函式的引數生成有狀態函式(C 簽名)。最好我還想讓它們(或它們的內部s->(T,s))可顯示。
我知道對于無狀態函式,我可以撰寫類似
type Compare = CInt -> CInt -> CBool
foreign import ccall "wrapper"
mkCompare :: Compare -> IO (FunPtr Compare)
但是我在嘗試這種有狀態函式的方法時遇到了困難,因為我看不到如何將隱藏在 Haskell 中的狀態的 monad 轉換為在 C 中隱藏狀態的函式。
有狀態函式 f 的示例
static int i = 0;
int f() {
return i ;
}
在 Haskell 中,我將此函式表示為State (\s -> (s,s 1)).
QuickCheck 與它有什么關系?
如果我有一個將有狀態函式作為引數的 C 函式,例如
int twice(int (*f)()) {
f();
return f();
}
然后我可以使用 QuickCheck 測驗該功能,其中 QuickCheck 可以為 生成不同的實作f,通常看起來類似于
prop_total (Fun f) xs = total $ g f xs
但是這些生成的函式是無狀態的,不像上面的示例 C 函式那樣有狀態。
uj5u.com熱心網友回復:
感謝 Daniel Wagner 在評論中的建議,我可以弄清楚。Show 實體是免費提供的。這是我運行的一個最小示例
gcc -fPIC -shared -o libstateful.dylib stateful.c && ghc -L. Stateful.hs -lstateful && ./Stateful
正如預期的那樣,它將輸出大約 50% 的 1(真)和 50% 的 0(假)的分布。
有狀態的.hs
import Data.IORef
import Foreign.C
import Foreign.Ptr
import System.IO.Unsafe
import Test.QuickCheck
instance CoArbitrary CInt where
coarbitrary = coarbitraryIntegral
instance Arbitrary CBool where
arbitrary = chooseEnum (0,1)
shrink 1 = [0]
shrink 0 = []
instance Function CInt where
function = functionIntegral
type Generator = IO CBool
foreign import ccall "wrapper" mkGenerator :: Generator -> IO (FunPtr Generator)
foreign import ccall "changes" changes :: FunPtr Generator -> IO CBool
type StateFn = CInt -> (CBool,CInt)
stateFnToIORef :: StateFn -> IORef CInt -> IO CBool
stateFnToIORef f s_ref = do
s <- readIORef s_ref
let (a,s') = f s
writeIORef s_ref s'
pure a
prop_changes :: Fun CInt (CBool,CInt) -> Property
prop_changes (Fn f) = unsafePerformIO (do
x_ref <- newIORef 0
f' <- mkGenerator $ stateFnToIORef f x_ref
res <- changes f'
pure $ collect res (total res))
main :: IO ()
main = quickCheck prop_changes
有狀態的.c
_Bool changes(_Bool (*f)()) {
_Bool x = f();
_Bool y = f();
return x != y;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/528512.html
標籤:哈斯克尔快速检查
上一篇:Haskell簽入串列
