嗨,我正在尝试编写一些基本代码来实现Bresenham算法,但我不得不尝试使用round和/.我的代码是:
bresenhamAlgorithm :: Coord -> Coord -> Int -> Int
bresenhamAlgorithm (x1, y1) (x2, y2) x'= round $ (fromIntegral ((y2 -
y1) * (x' - x1)) / fromIntegral (x2 - x1)) + y1
Run Code Online (Sandbox Code Playgroud)
我不断收到No instance for (Fractional Int) arising from a use of ‘/’和No instance for (RealFrac Int) arising from a use of ‘round’错误存在的.我不明白,因为我相信fromIntegral会将分子和分母转换为允许使用该/操作的分数?
我不明白,因为我认为fromIntegral会将分子和分母转换为允许使用/ operation的小数?
是的,你的理解基本上是正确的,但你做了一个小的疏忽.
这里的代码格式略有不同:
bresenhamAlgorithm :: Coord -> Coord -> Int -> Int
bresenhamAlgorithm (x1, y1) (x2, y2) x'= round $
(
fromIntegral ((y2 - y1) * (x' - x1))
/ fromIntegral (x2 - x1)
) + y1
Run Code Online (Sandbox Code Playgroud)
这是(因为+绑定强于$)相当于:
bresenhamAlgorithm :: Coord -> Coord -> Int -> Int
bresenhamAlgorithm (x1, y1) (x2, y2) x'= round (
(
fromIntegral ((y2 - y1) * (x' - x1))
/ fromIntegral (x2 - x1)
) + y1)
Run Code Online (Sandbox Code Playgroud)
这里的问题实际上既不是也不round是/,最后是你+ y1的问题.因为y1已经知道Int,类型检查器试图统一
fromIntegral ((y2 - y1) * (x' - x1)) / fromIntegral (x2 - x1)
Run Code Online (Sandbox Code Playgroud)
与Int,当然失败,因为/不允许Int.
解决方案是添加另一个 fromIntegral:
bresenhamAlgorithm :: Coord -> Coord -> Int -> Int
bresenhamAlgorithm (x1, y1) (x2, y2) x'= round $
(
fromIntegral ((y2 - y1) * (x' - x1))
/ fromIntegral (x2 - x1)
) + fromIntegral y1 -- we need y1 as a fractional
Run Code Online (Sandbox Code Playgroud)
或者你也可以把所有东西+ y1包括在内 - 包括round括号中的- 也可以.
现在之前未捕获的原因是因为fromIntegral实际上可以将整数类型转换为任何数字类型...包括它们自己.所以在这种情况下,因为表达是如何写的typechecker推断,你的意思是fromIntegral要转换Int为... Int一次.这不是你的意思,但编译器不知道.
如果我们添加一个小辅助函数:
toDouble :: Int -> Double
toDouble = fromIntegral
Run Code Online (Sandbox Code Playgroud)
并在你的定义中使用它而不是 fromIntegral
bresenhamAlgorithm :: Coord -> Coord -> Int -> Int
bresenhamAlgorithm (x1, y1) (x2, y2) x'= round $
(
toDouble ((y2 - y1) * (x' - x1))
/ toDouble (x2 - x1)
) + y1
Run Code Online (Sandbox Code Playgroud)
为了强制转换,我们实际上得到了一个更有用的错误消息:
• Couldn't match expected type ‘Double’ with actual type ‘Int’
• In the second argument of ‘(+)’, namely ‘y1’
In the second argument of ‘($)’, namely
‘(toDouble ((y2 - y1) * (x' - x1)) / toDouble (x2 - x1)) + y1’
In the expression:
round
$ (toDouble ((y2 - y1) * (x' - x1)) / toDouble (x2 - x1)) + y1
) + y1
^^
Run Code Online (Sandbox Code Playgroud)