我在haskell GHCI上编写遗传算法
当我输入children ["+ 1 2","* 3 4"]
GHCI写"
并挂断:(
所有函数分开工作,只有在一起使用函数(交叉,rnd3,单独的gNt工作规范)和随机数时才会出现错误。
代码:
----- Random IO Int -----------------------------------
rnd3 :: Int->IO Int
rnd3 x= do
oldState <- getStdGen
let (result,newState) = randomR (1,x) oldState
setStdGen newState
return (result)
---------------- getNtexp ------------------------------ ----------
gNt :: String->Int->String
gNt l n = unwords ( gNtWords n (words l) )
opX :: [String] -> [String]
opX (fst:x) = helper 1 x []
where
helper 0 l ans = reverse ans
helper n (fst:x) ans = if ( fst == "+" || fst == "-" || fst == "*" || fst == "/" ) then helper (n+1) x (fst:ans)
else helper (n-1) x (fst:ans)
opY :: [String] -> [String]
opY (fst:x) = helper 1 x []
where
helper 0 l ans = l
helper n (fst:x) ans = if ( fst == "+" || fst == "-" || fst == "*" || fst == "/" ) then helper (n+1) x (fst:ans)
else helper (n-1) x (fst:ans)
gNtWords:: Int -> [String] -> [String]
gNtWords n [] = []
gNtWords 0 l = l
gNtWords 1 l = (opX l)
gNtWords 2 l = (opY l)
gNtWords n l = if( n < (length (opX l) + 2 ) ) then gNtWords (n - 2 ) (opX l)
else gNtWords (n - (length (opX l)) - 1 ) (opY l)
-- ( gNtWords (n + nodeCount (opX l) ) (opY l) ) )
----------------------替换NtSubExp ----------------------- -----------
rNt :: String->String->Int->String
rNt expTree newExp n = unwords (rNtWord n (words expTree) (words newExp) )
rNtWord:: Int -> [String] -> [String] -> [String]
rNtWord n l newExp = replacer n l newExp
where
replacer 0 l newExp = newExp
replacer 1 (l) newExp = ( (++) [head l] ( (++) newExp (opY l) ) )
replacer 2 (l) newExp = ( (++) [head l] ( (++) (opX l) newExp ) )
replacer n l newExp = if( n < (length (opX l) + 2 ) ) then (++) [head l] ((++) (replacer (n - 2)(opX l) newExp ) (opY l))
else (++) [head l] ( (++) (opX l) (replacer(n-(length(opX l))-1)(opY l) newExp ))
---------------------交叉------------------------- -----------------
crossover :: String->String->String
crossover exp1 exp2 = let rnd1 = ( unsafePerformIO (rnd3 (nCount exp1) ) ) -1
;rnd2 = (unsafePerformIO (rnd3 (nCount exp2) )) - 1
in rNt exp1 (gNt exp2 rnd2) rnd1
----------正态分布------------------------------------ ---
norm :: Int -> Float
norm size = let sizeF = fromIntegral (size)
;rnd1 = ( fromIntegral ( unsafePerformIO (rnd3 2000 ) ) )/1000 - 1
;rnd2 = ( fromIntegral ( unsafePerformIO (rnd3 2000 ) ) )/1000 - 1
;s = rnd1*rnd1 +rnd2*rnd2
in ( cos (2.0 * 3.14 * rnd1 ) * sqrt( -2.0*log(rnd2) ))
------------------------ makeChildren --------------
parent:: [String] -> String
parent pop = let rnd = ( unsafePerformIO (rnd3 (length pop) ) ) - 1
in (!!) pop rnd
如果父级中的rnd不是随机数(例如rnd = 1或rnd = 2),则一切正常
children:: [String] -> String
children pop = crossover (parent pop) (parent pop)
或者如果此处(parent pop)
或(++) (parent pop) (parent pop)
全部有效
出了什么问题?在我看来,或者我不知道如何随机数字(在其他功能,他们正常工作)抱歉我的英语(和haskell))
答案 0 :(得分:2)
没有理由在这里使用unsafePerformIO
,或者几乎没有理由使用rnd3
。只是假装它不存在。它不会使您的代码更好,更易于阅读或编写,并且通常会使代码的副作用无法正常工作。基础知识有many good tutorials - 特别是monad。我强烈建议你选择一个并完成整个事情(第一个是好的)。
作为旁注,您对rnd3 x = randomRIO (1,x)
的定义完全等同于crossover exp1 exp2 = do
rnd1 <- rnd3 (nCount exp1)
rnd2 <- rnd3 (nCount exp2)
return $ rNt exp1 (gNt exp2 (rnd2 - 1)) (rnd1 - 1)
let x = ... unsafePerformIO ..
只要您拥有x <- ...
,只需将其删除并将其替换为rnd1 <- rnd3 (nCount exp1) - 1
即可。请注意,您无法编写rnd1 <- fmap (subtract 1) $ rnd3 (nCount exp1)
,但可以编写let
。
您可以在do
块中拥有in
。语法略有不同;您不需要撰写let
(或者更确切地说,in
之后的所有内容都隐含norm sizeF = do
let sizeF = fromIntegral size -- this is unused?
rnd1' <- rnd3 2000
rnd2' <- rnd3 2000
let
rnd1 = rnd1' / 1000 - 1
rnd2 = rnd2' / 1000 - 1
s = rnd1*rnd1 +rnd2*rnd2
return $ cos (2.0 * 3.14 * rnd1) * sqrt(-2.0*log rnd2)
。)
IO
要记住的一件重要事情是你无法摆脱do
。 IO a
块中的最后一个语句必须具有{{1}}类型。
答案 1 :(得分:-1)
我的决定:起初我在移动Int的基础上编写了素数生成器
myRandom :: Int -> Int -> Int
myRandom gen range= let a = 6364136223846793005
;c = 1442695040888963407
;m = 2^32--2^64
in mod(mod (a*gen + c) (2^16)) range
随着两个在32 \ 64度分割成零的结果?
收到休闲Int是发电机的以下入口值。然后我明白了,我们隐藏成功StdGen可以存储,而不是Int在一个挑衅的函数
rand :: StdGen->Int->(Int,StdGen)
rand gen range= randomR (0,range-1) gen
第一代使用mkStdGen(使用unsafePerformIO ..来自我的rnd3麻木)