尝试学习一些F#,我遇到了几个挂断。
以下是代码:
#light
module HtmlModule
type HtmlString(text:string) =
override x.ToString() = text
type HtmlAttribute(key:string, value:string) =
inherit HtmlString(key + "=\"" + value + "\"");
type HtmlElement(tag: string, ?contents:list<'a> when 'a :> HtmlString) =
inherit HtmlString("")
let innerContents = defaultArg contents []
let castToHtmlAttribute (hs:HtmlString) : Option<HtmlAttribute> =
match hs with
| :? HtmlAttribute as temp -> Some(temp)
| _ -> None
member x.tag = tag
member x.contents = innerContents |> List.filter(fun x -> (castToHtmlAttribute x).IsNone)
member x.attributes = innerContents |> List.map(fun x -> (castToHtmlAttribute x)) |> List.filter(fun x-> x.IsSome) |> List.map(fun x->x.Value)
override x.ToString() =
let sb = System.Text.StringBuilder()
sb.Append("<" + x.tag)
for att in x.attributes do
sb.Append(" " + att.ToString())
sb.Append(">")
for item in x.contents do
sb.Append(item.ToString())
sb.Append("</" + x.tag + ">")
sb.ToString()
let element tag contents = new HtmlElement(tag, contents)
let div contents = element "div" contents
let p contents = element "p" contents
let text text = new HtmlString(text)
let attr key value = new HtmlAttribute(key, value)
let classes value = attr "class" value
和一个快速控制台程序来显示问题:
#light
open HtmlModule
let stuff = [for a in 1 .. 10 do yield p [text ("some String " + a.ToString())]]
let elem = div [
attr "class" "someClass";
text "This is some inner text";
div stuff;
]
let result = elem.ToString()
printfn "%A" result
编译器不允许该行
div stuff;
它声明:
“错误7类型不匹配。期待HtmlString列表但给出HtmlElement列表类型'HtmlString'与类型'HtmlElement'不匹配”
可以将此问题跟踪到castToHtmlAttribute
方法签名
let castToHtmlAttribute (hs:HtmlString) : Option<HtmlAttribute> =
如果我像这样使这一行变得更通用:
let castToHtmlAttribute (hs:'a when 'a :> HtmlString) : Option<HtmlAttribute> =
我收到一个新错误:
“错误2此类运行时强制或类型测试从类型'a到HtmlAttribute涉及基于此程序点之前的信息的不确定类型。某些类型不允许运行时类型测试。需要进一步的类型注释。”
感谢任何帮助。
答案 0 :(得分:3)
这里的诊断不是很好。
您可以像这样修复代码:
let stuff = [for a in 1 .. 10 do
yield (p [text ("some String " + a.ToString())]) :> HtmlString]
我在基本类型中插入了一个显式的upcast。
答案 1 :(得分:1)
期望HtmlString列表但给出HtmlElement列表类型'HtmlString'与类型'HtmlElement'不匹配“
这很好地说明了这个问题。对于F#,List<HTMLElement>
不是List<HTMLString>
,而List<Orange>
不是List<Fruit>
。
如果是,你可以写
Apple :: oranges
由于这没有任何意义,F#希望你明确地转发。只需告诉div
使用通用列表。
简而言之,您可以将类型HTMLString list
更改为多态#HTMLString list
或手动转换参数或stuff
。