作为学习Haskell过程中的个人练习,我试图将这个F#片段移植到随机艺术中.
我没有嵌入完整的源代码,没有膨胀这个问题,但可以作为要点.
该计划的一个重要部分是这种Expr
类型:
data Expr =
VariableX
| VariableY
| Constant
| Sum Expr Expr
| Product Expr Expr
| Mod Expr Expr
| Well Expr
| Tent Expr
| Sin Expr
| Level Expr Expr Expr
| Mix Expr Expr Expr
deriving Show
Run Code Online (Sandbox Code Playgroud)
和两个功能:
gen :: Int -> IO Expr
在给定多次迭代的情况下,随机生成树状结构
eval :: Expr -> IO (Point -> Rgb Double)
遍历树并终止生成绘图功能.
传递给gen
更高的数字是产生以下异常的概率:Ratio has zero denominator
.
我是Haskell的新手,所以要解决我尝试编译的问题,如上所述:
ghc RandomArt.hs -prof -auto-all -caf-all
Run Code Online (Sandbox Code Playgroud)
只获得这个(对我来说没用)信息:
$ ./RandomArt +RTS -xc
*** Exception (reporting due to +RTS -xc): (THUNK_STATIC), stack trace:
GHC.Real.CAF
--> evaluated by: Main.eval.\,
called from Main.eval,
called from Main.tga.pxs',
called from Main.tga,
called from Main.save,
called from Main.main,
called from :Main.CAF:main
--> evaluated by: Main.eval.\.r,
called from Main.eval.\,
called from Main.eval,
called from Main.tga.pxs',
called from Main.tga,
called from Main.save,
called from Main.main,
called from :Main.CAF:main
*** Exception (reporting due to +RTS -xc): (THUNK_STATIC), stack trace:
Main.tga,
called from Main.save,
called from Main.main,
called from GHC.Real.CAF
RandomArt: Ratio has zero denominator
Run Code Online (Sandbox Code Playgroud)
将生成的函数持久保存到TGA文件的代码可以正常工作,因为它是我之前的excercize(来自OCaml的端口).
我尝试Expr
从GHCi执行各种树,手工组装数据或在程序中应用函数但我无法识别错误.
Haskell文档讨论了一个名为loch
应该能够编译保留源代码行号的包,但我无法安装它(我通常安装cabal install
我需要的每个包).
问题,说实话是两个:
哪个是bug(在这种特定情况下)?
我需要掌握哪个工具才能找到这样的bug(或者一般的bug)?
提前致谢.
让我们首先关注异常.
哪个是bug(在这种特定情况下)?
在mod'
.如果我们提供替代版本而不是一个版本,我们可以轻松地检查这个Data.Fixed
:
mod' :: RealFrac a => a -> a -> a
mod' _ 0 = error "Used mod' on 0"
mod' a b =
let k = floor $ a / b
in a - (fromInteger k) * b
Run Code Online (Sandbox Code Playgroud)
我们现在得到 Used mod' on 0
.
我需要掌握哪个工具才能找到这样的bug(或者一般的bug)?
在这种情况下,必要的提示已经在异常的消息中:
Run Code Online (Sandbox Code Playgroud)Ratio has zero denominator
这意味着在a的上下文中有一个除以零的地方Ratio
.所以你需要照顾你划分东西的所有地方.因为你只使用(/)
和mod'
,归结为它们中的一个是否真的可以抛出这个异常:
(/)
±Infinity
如果使用Double
,通常会按除以零返回,mod'
toRational
内部使用,这是一个Ratio Integer
.所以只有一个罪魁祸首.请注意,如果b
不为零,则其他实现会产生相同的结果.
使用mod
或mod'
使用b == 0
没有明确定义.毕竟,模运算应该包含以下属性:
prop_mod :: Integral n => n -> n -> Bool
prop_mod a b =
let m = a `mod` b
d = a `div` b
in a == b * d + m -- (1)
&& abs m < abs b -- (2)
Run Code Online (Sandbox Code Playgroud)
如果b == 0
,则不存在任何对(d, m)
(1)和(2)成立的对.如果我们放松这个法律并扔掉(2),结果mod
不再是唯一的.这导致以下定义:
mod' :: RealFrac a => a -> a -> a
mod' a 0 = a -- this is arbitrary
mod' a b =
let k = floor $ a / b
in a - (fromInteger k) * b
Run Code Online (Sandbox Code Playgroud)
但是,这是一个任意的定义.你必须问自己,"如果我不能mod
以理智的方式使用,我真正想做什么".由于F#显然没有抱怨a % 0
,看看他们的文档.
无论哪种方式,您都不能使用库mod
函数,因为它们没有为零分母定义.
归档时间: |
|
查看次数: |
249 次 |
最近记录: |