【发布时间】:2016-05-17 00:39:49
【问题描述】:
我有三种类型的位置 - 称为 Position、WalkPosition 和 TilePosition。我已经将它们转换为度量单位,它更简洁,但有些东西对我来说不太适用。
不幸的是,我没有使用纯粹的 F#(有一个通过 CLI 公开的 C++ 接口 - 很有趣!)。首先,为了转换输入和输出,我使用了 * 1
[<Measure>] type pixel
[<Measure>] type walk
[<Measure>] type tile
module Position =
type Position<[<Measure>] 'u> = Pos of int<'u> * int<'u> with
static member inline (+) (Pos (x1, y1), Pos (x2, y2)) = Pos (x1 + x2, y1 + y2)
static member inline (-) (Pos (x1, y1), Pos (x2, y2)) = Pos (x1 - x2, y1 - y2)
static member inline (*) (Pos (x, y), f) = Pos (x * f, y * f)
static member inline (/) (Pos (x, y), d) = Pos (x / d, y / d)
// getApproxDistance as per Starcraft: Broodwar
static member (|~|) (Pos (x1, y1), Pos (x2, y2)) =
let xDist = abs (x1 - x2)
let yDist = abs (y1 - y2)
let largeDist, smallDist = max xDist yDist, min xDist yDist
if smallDist < (largeDist >>> 2) then largeDist
else
let smallCalc = (3*smallDist) >>> 3
((smallCalc >>> 5) + smallCalc + largeDist - (largeDist >>> 4) - (largeDist >>> 6))
// Precise length calc - may be slow
static member inline (|-|) (Pos (x1, y1), Pos (x2, y2)) =
pown (x1 - x2) 2 + pown (y1 - y2) 2 |> float |> sqrt
let inline posx (Pos (_x, _)) = _x
let inline posy (Pos (_, _y)) = _y
let PixelPerWalk : int<pixel/walk> = 8<pixel/walk>
let PixelPerTile : int<pixel/tile> = 32<pixel/tile>
let WalkPerTile : int<walk/tile> = 4<walk/tile>
let inline walkToPixel (pos:Position<_>) = pos * PixelPerWalk
let inline tileToPixel (pos:Position<_>) = pos * PixelPerTile
let inline pixelToWalk (pos:Position<_>) = pos / PixelPerWalk
let inline tileToWalk (pos:Position<_>) = pos * WalkPerTile
let inline pixelToTile (pos:Position<_>) = pos / PixelPerTile
let inline walkToTile (pos:Position<_>) = pos / WalkPerTile
let example = Pos (1<walk>, 2<walk>) |~| Pos (2<walk>, 1<walk>)
我很乐意撕掉度量单位(|> int 在这种情况下似乎不会减慢它)并将其添加回返回的距离,但似乎我不能这样做。我什至不能重载内联调用,因为你不能纯粹在度量单位上重载。想法?
【问题讨论】:
-
你说你不能超载计量单位。在某些情况下它可以工作,你想重载什么?你能展示一个(不工作的)示例代码吗?
-
我不清楚到底是什么问题。上面的代码可以编译,所以我认为它是别的东西?
-
在底部添加了一个失败的例子,并说明了类型签名不正确的原因。