【问题标题】:F# type definition with expression带有表达式的 F# 类型定义
【发布时间】:2012-12-30 10:14:20
【问题描述】:

是否可以这样表达:

type id = int > 0

我知道它不可能静态地执行,因为这意味着 F# 具有依赖类型。在 C# 中,我习惯于用代码契约来做这种事情并获得运行时强制。我在这里寻找类似的东西。

谢谢

编辑: 感谢您提供各种利弊的答案。目前我只使用 F# 的一个小子集,它是 ocaml 核心的一个子集,可以轻松地进行编程证明。所以没有课。

【问题讨论】:

    标签: f#


    【解决方案1】:

    与其他人所说的相反,如果我正确理解您的问题,我建议不要在此处使用类
    由于该值是不可变,我们只需要应用一次约束。任何包装类都将是开销和负载 GC。相反,一个简单的函数就可以完成这项工作:

    let inline constrained predicate errormessage value =
        if not (predicate value)
        then invalidArg "value" errormessage
        else value
    
    let positive =
        constrained (fun x -> x > 0) "Value must be positive"
    
    let int1 = positive 5      // OK
    let int2 = positive -3     // ArgumentException
    

    你可以对其他类型做同样的事情:

    let mustBeLong =
        constrained (fun (x:string) -> x.Length > 3) "String must be long"
    
    let str1 = mustBeLong "foobar"  // OK
    let str2 = mustBeLong "baz"     // ArgumentException
    

    在结构中使用相同的:

    type Point2D =
       struct 
          val X: int
          val Y: int
          new(x: int, y: int) = { X = positive x; Y = positive y }
       end
    
    let point1 = Point2D(5, 3)  // OK
    let point2 = Point2D(5, -2) // ArgumentException
    

    【讨论】:

      【解决方案2】:

      定义为联合类型:

      type Id = Id of int
      

      并用另一个函数隐藏构造函数:

      let Id n =
        assert(n > 0)
        Id n
      

      【讨论】:

      • 这个表达式应该是单位但是 int
      【解决方案3】:

      在 F# 中,您必须求助于类并检查构造函数中的参数。其他类型(例如可区分联合、记录和结构)具有隐式构造函数,您无法轻易更改。

      type Id(i: int) =
          do if i <= 0 then 
               invalidArg "i" "the argument has to be a positive integer"
          member x.Value = i
      

      模式匹配不能很好地与类一起使用。您可以使用活动模式解决问题:

      let (|Id|) (id: Id) = id.Value
      
      let id = Id(1)
      
      match id with
      | Id 1 -> printfn "matched"
      | _ -> printfn "unmatched"
      

      【讨论】:

        【解决方案4】:

        你可以像这样创建一个通用类:

        type verify<'t>(t:'t,cond) =
            let mutable tval = t
            let _verify v = if not (cond v) then failwith "bad argument"
            do _verify tval
            member x.get() = tval
            member x.set v =
                _verify v 
                tval <- v
        

        然后你可以使用它

        verify(1,fun t -> t>0)
        

        使用.set 将重新检查条件。

        【讨论】:

        • 你是认真的吗?换句话说,在学习 f# 的基础知识之前你需要有一个 phd 吗? -1
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多