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只能静态接受元音,而不是如上所述,在运行时检查它.
我们怎样才能做到这一点?有谁有想法吗?必须有一个聪明的方法来做到这一点.如果没有工会案例,可能还有接口?我一直在努力解决这个问题,但我被困在盒子里,无法想到它.
看起来该库使用了 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)