F# 类型和函数签名

标签 f# type-inference

我是 F# 的新手,我正在尝试做一些事情来了解这门语言。

我必须有两种几乎相同的类型(坐标和矢量)。由于这种类型推断无法正常工作,我很难在每个函数上指定正确的类型。

它不知何故不明白这是一个向量:

type Coordinate = {X:int; Y:int}
type Vector = {X:int; Y:int}

let calculateVector (origin:Coordinate) (destination:Coordinate) = { X=destination.X-origin.X; Y= destination.Y-origin.Y;}

在这里,当我想要坐标的返回类型时,我找不到如何为此函数指定返回值:
let calculateNextCoordinate (coordinate:Coordinate) direction = 
   match direction with
   | "N" -> { X=coordinate.X; Y=coordinate.Y-1 }
   | "NE" -> { X=coordinate.X+1; Y=coordinate.Y-1 }
   | "E" -> { X=coordinate.X+1; Y=coordinate.Y }
   | "SE" -> { X=coordinate.X+1; Y=coordinate.Y+1 }
   | "S" -> { X=coordinate.X; Y=coordinate.Y+1 }
   | "SW" -> { X=coordinate.X-1; Y=coordinate.Y+1 }
   | "W" -> { X=coordinate.X-1; Y=coordinate.Y }
   | "NW" -> { X=coordinate.X-1; Y=coordinate.Y-1 }
   | _ -> coordinate

我在默认情况下有这个错误:这个表达式应该有“向量”,但这里有类型“坐标”

我厌倦了在此网站上查看函数签名,但无法解决我的问题:https://fsharpforfunandprofit.com/posts/function-signatures/

问题:

你如何解决这个错误?

是否因为推理类型默认采用与属性匹配的最后一个类型(在我的示例 Vector 中)?

奖励:在 F# 中是否有更好的方法来处理这种情况?

提前致谢

最佳答案

由于记录是使用其成员名称构造的:

{ X = 2; Y = 3}

您在 Vector 和 Coordinate 之间创建了命名冲突。在 F# 中,在这种情况下,编译器总是解析为最新定义,因此,在您的示例中,编译器会将记录 { X = ..., Y = ...} 解释为向量。

F# records on fsharpforfunandprofit.com上有好文章,这解释了如何轻松处理这个问题,我建议你阅读它以获得一个很好的解释。

但简而言之,您可以使用记录类型为记录实例的任一成员添加前缀:
{ Coordinate.X = 2; Y = 3 }  // Creates a Coordinate
{ X = 2; Coordinate.Y = 3 }  // Creates a Coordinate


{ Vector.X = 2; Y = 3 } // creates a vector

关于F# 类型和函数签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45381438/

相关文章:

typescript - 未推断出扩展接口(interface)的通用类型

scala - 为什么 Scala 类型与预期的 Int 不匹配?

azure - 输入绑定(bind)到自定义类似乎不适用于 blob

f# - 如何从 F# 调用 Q# 操作

java - 推理变量具有不兼容的界限。 Java 8 编译器回归?

functional-programming - 自底向上 Hindley-Milner 类型推断 : Applying a substitution to an implicit constraint

oop - 如何将 Haskell 类型类转换为 F#?

f# - 避免 "Incomplete pattern match"警告的替代方法

f# - F#类型提供者如何在编译时检查类型

c# - "x => { throw .. }"的 Lambda 推断匹配重载方法中的 Func<T,Task>?