haskell挂机(randomR,unsafePerformIO)

时间:2014-01-22 20:34:41

标签: haskell

我在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))

2 个答案:

答案 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

要记住的一件重要事情是你无法摆脱doIO 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麻木)