编辑:已更新,以包含整个代码。
我对Haskell很新,并且我遇到了一个程序问题,我已编写过为课程分配做一些熵计算(分配是计算,Haskell的使用是一个选择,所以我'我没有要求别人为我做作业,在Python中这需要花费大量的时间和精力来完成这项工作。代码采用一维数组:
--- first input (length 2):
--- 0,0 0,1 1,0 1,1
--- [.48, .02, .02, .48]
--- or:
--- 0 1
--- .48 .02 0
---
--- .02 .48 1
然后我定义了几个通用函数:
log2 :: Float -> Float
log2 x =
logBase 2 x
entropy :: [Float] -> Float
entropy probArray =
sum(map (\i -> (i * (log2 (1/i)))) probArray)
以及每项具体计算的功能:
-- calculate joint entropy
jointEntropy :: [Float] -> Float
jointEntropy probArray =
entropy probArray
-- calculate entropy of X
splitByCol :: Int -> [Float] -> [[Float]]
splitByCol length probArray =
[(take length probArray)] ++ (splitByCol length (drop length probArray))
xEntropy :: Int -> [Float] -> Float
xEntropy length probArray =
entropy (map sum (splitByCol length probArray))
-- calculate entropy of Y
ithElements :: Int -> Int -> [Float] -> [Float]
ithElements level length matrixArray =
let indexArray = zip [0..(length^2 - 1)] matrixArray
in [snd x | x <- indexArray, fst x `mod` length == level]
splitByRow :: Int -> Int -> [[Float]] -> [[Float]]
splitByRow level length lists =
if level == length
then
tail lists -- return list sans full matrix array which was being carried at the front
else
splitByRow (level+1) length (lists ++ [(ithElements level length (lists !! 0))])
yEntropy :: Int -> [Float] -> Float
yEntropy length probArray =
entropy (map sum (splitByRow 0 length [probArray]))
--calculate mutual information
mutualInfo :: Float -> Float -> Float
mutualInfo xEnt yEnt =
xEnt - yEnt
-- calculate conditional of X given Y - (X|Y)
xCond :: Float -> Float -> Float
xCond xEnt mInfo =
xEnt - mInfo
-- calculate conditional of Y given X - (Y|X)
yCond :: Float -> Float -> Float
yCond yEnt mInfo =
yEnt - mInfo
然后将它们链接在一起以返回一个数组,其中包含我想要执行的每个计算:
-- caller functions -> resArray ends up looking like [H(X,Y), H(X), H(Y), I(X;Y), H(X|Y), H(Y|X)]
calcJointEnt :: [Float] -> [Float]
calcJointEnt probArray =
calcVarEnt probArray [(jointEntropy probArray)]
calcVarEnt :: [Float] -> [Float] -> [Float]
calcVarEnt probArray resArray =
let len = floor (sqrt (fromIntegral (length probArray)))
in calcMutual probArray (resArray ++ [(xEntropy len probArray), (yEntropy len probArray)])
calcMutual :: [Float] -> [Float] -> [Float]
calcMutual probArray resArray =
calcCond probArray (resArray ++ [(mutualInfo (resArray !! 1) (resArray !! 2))])
calcCond :: [Float] -> [Float] -> [Float]
calcCond probArray resArray =
resArray ++ [(xCond (resArray !! 1) (resArray !! 3)), (yCond (resArray !! 2) (resArray !! 3))]
等等......然后我有一些函数来格式化打印字符串,以及一个将它们组合在一起的主要功能:
-- prepare printout
statString :: (String, String) -> String
statString t =
(fst t) ++ ": " ++ (snd t)
printOut :: [Float] -> String
printOut resArray =
let statArray = zip ["H(X,Y)", "H(X)", "H(Y)", "H(X;Y)", "H(X|Y)", "H(Y|X)"] (map show resArray)
in "results:\n\t" ++ intercalate "\n\t" (map statString statArray) ++ "\n\n---\n"
-- main
main :: IO()
main =
let inputs = [[0.48, 0.02, 0.02, 0.48], [0.31, 0.02, 0.00, 0.02, 0.32, 0.02, 0.00, 0.02, 0.29]]
in putStrLn (intercalate "" (map printOut (map calcJointEnt inputs)))
所以我确信有更好的方法可以做很多这样的事情,但在我看来,我的最小的haskell经验和我稍微扩展但仍然有限的功能方式编程体验应该有用。
我的问题是,当我编译并运行时,我得到了这个输出:
bash-4.2$ ./noise
results:
H(X,Y): 1.2422923
noise: out of memory (requested 1048576 bytes)
在打印出的一个结果与内存错误消息之间有大量时间。当我在ghci调试器(我第一次使用它)中打开它时,如果我试图在printOut函数中强制执行resArray,它会执行相同的操作,并且当我尝试依次解压缩resArray时最低级别的链接功能:
calcCond :: [Float] -> [Float] -> [Float]
calcCond probArray resArray =
resArray ++ [(xCond (resArray !! 1) (resArray !! 3)), (yCond (resArray !! 2) (resArray !! 3))]
我得到以下内容:
[noise.hs:101:3-96] *Main> seq _t1 ()
()
[noise.hs:101:3-96] *Main> :print resArray
resArray = (_t2::Float) : (_t3::[Float])
[noise.hs:101:3-96] *Main> seq _t2 ()
()
[noise.hs:101:3-96] *Main> :print resArray
resArray = 1.2422923 : (_t4::[Float])
[noise.hs:101:3-96] *Main> seq _t3 ()
()
[noise.hs:101:3-96] *Main> :print resArray
resArray = 1.2422923 : (_t5::Float) : (_t6::[Float])
[noise.hs:101:3-96] *Main> seq _t5 ()
^C^C^C^C^CInterrupted.
[noise.hs:101:3-96] *Main>
我查看了RTS调试工具,它似乎是推荐的工具,用于在网站上类似提出的问题中为这样的事情打开引擎盖,但是当我用+ RTS -xc运行时没有发生任何事情。我认为这是因为RTS似乎要求它实际抛出一个异常,而不是操作系统踩到它?
我认为自己来自命令性背景的主要问题是,程序可以通过某种无限循环过程到达IO语句的概念仍然在逻辑的某个地方进行,这是一个外来概念。当然,我可能完全不正确,这是正在发生的事情,但这对我来说似乎是这样。你们所有人都可以给予的任何帮助(不仅仅是关于这段代码,而且通常也是我对Haskell的方法),我们将不胜感激。
答案 0 :(得分:0)
由于永远不会打印H(X)
,因此查看计算结果是有意义的,即xEntropy
。 xEntropy
调用splitByCol
,其中有一个明显的错误。它返回一个无限的列表!这意味着entropy
永远不会终止,因为它会尝试在无限列表上调用sum
。