F#和静态检查的联合案例

Joh*_*son 7 html f# code-contracts

很快我和我的兄弟Joel将发布Wing Beats的 0.9版本.它是用F#编写的内部DSL.有了它,您可以生成XHTML.其中一个灵感来源是Ocsigen框架的XHTML.M模块.我不习惯OCaml语法,但我确实理解XHTML.M以某种方式静态检查元素的属性和子元素是否是有效类型.

我们无法在F#中静态检查相同的内容,现在我想知道是否有人知道如何做到这一点?

我的第一个天真的方法是将XHTML中的每个元素类型表示为一个联合案例.但遗憾的是,您无法静态限制哪些案例作为参数值有效,如XHTML.M中所示.

然后我尝试使用接口(每个元素类型为每个有效父类实现一个接口)和类型约束,但是我没有设法使它工作而不使用显式转换,使得解决方案使用起来很麻烦.无论如何,它并不像一个优雅的解决方案.

今天我一直在寻找Code Contracts,但它似乎与F#Interactive不兼容.当我按下alt +输入它冻结.

只是为了让我的问题更加清晰.这是一个同样问题的超简单人工例子:

type Letter = 
    | Vowel of string
    | Consonant of string
let writeVowel = 
    function | Vowel str -> sprintf "%s is a vowel" str
Run Code Online (Sandbox Code Playgroud)

我希望writeVowel只能静态接受元音,而不是如上所述,在运行时检查它.

我们怎样才能做到这一点?有谁有想法吗?必须有一个聪明的方法来做到这一点.如果没有工会案例,可能还有接口?我一直在努力解决这个问题,但我被困在盒子里,无法想到它.

kvb*_*kvb 4

看起来该库使用了 O'Caml 的多态变体,这些变体在 F# 中不可用。不幸的是,我也不知道在 F# 中对它们进行编码的可靠方法。

一种可能性可能是使用“幻像类型”,尽管我怀疑考虑到您正在处理的不同类别内容的数量,这可能会变得笨拙。以下是处理元音示例的方法:

module Letters = begin
  (* type level versions of true and false *)
  type ok = class end
  type nok = class end

  type letter<'isVowel,'isConsonant> = private Letter of char

  let vowel v : letter<ok,nok> = Letter v
  let consonant c : letter<nok,ok> = Letter c
  let y : letter<ok,ok> = Letter 'y'

  let writeVowel (Letter(l):letter<ok,_>) = sprintf "%c is a vowel" l
  let writeConsonant (Letter(l):letter<_,ok>) = sprintf "%c is a consonant" l
end

open Letters
let a = vowel 'a'
let b = consonant 'b'
let y = y

writeVowel a
//writeVowel b
writeVowel y
Run Code Online (Sandbox Code Playgroud)