我有三种类型的位置 - 名为Position,WalkPosition和TilePosition。我已将它们转换为测量单位,并且它更清晰,但有些事情对我来说并不适用。
不幸的是,我没有使用纯粹的F#(通过CLI公开了一个C ++界面 - 有趣的时候!)。首先,对于转换和转出,我使用了* 1< tile>和* 1< 1 / tile>因为我注意到我使用int的性能受到了影响。在我开始尝试使用泛型做有趣的事情之前,这一切都很好。我目前被getApproxDistance函数困扰,我正在调用一个运算符|〜|。假设此版本没有附加到我的职位的计量单位:
[<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>)
我会满足于关闭度量单位(|&gt; int在这种情况下似乎没有减慢速度)并将其添加回返回的距离,但似乎我做不到。我甚至无法重载内联调用,因为您不能仅仅在度量单位上过载。想法?
答案 0 :(得分:4)
您看到的错误是因为|~|
函数中的度量单位被限制为1
。这意味着int<walk>
不是此函数的有效输入。
您是正确的int
函数将从int<'u>
类型的某些内容中删除度量单位。您可能不知道的是,您可以使用LanguagePrimitives.Int32WithMeasure<'u>
添加特定的度量单位。
因此,您可以撰写|~|
:
static member (|~|) (Pos (x1 : int<'u>, y1 : int<'u>), Pos (x2 : int<'u>, y2 : int<'u>)) =
let xDist = abs (int x1 - int x2)
let yDist = abs (int y1 - int y2)
let largeDist, smallDist = max xDist yDist, min xDist yDist
if smallDist < (largeDist >>> 2) then
largeDist
|> LanguagePrimitives.Int32WithMeasure<'u>
else
let smallCalc = (3*smallDist) >>> 3
((smallCalc >>> 5) + smallCalc + largeDist - (largeDist >>> 4) - (largeDist >>> 6))
|> LanguagePrimitives.Int32WithMeasure<'u>
你的例子:
let example = Pos (1<walk>, 2<walk>) |~| Pos (2<walk>, 1<walk>)
然后具有正确的类型:int<walk>
。
您不应该担心剥离/添加度量单位对性能的影响,它们只是一个编译时构造 - 度量信息不会在运行时保留。
顺便说一句,您并不是真的需要所有这些inline
个关键字,您没有使用静态解析的类型参数做任何事情,有关更多详细信息,请参阅https://msdn.microsoft.com/en-us/library/dd548047.aspx关于使用inline
。