【问题标题】:Resuse F# Active Pattern result重用 F# Active Pattern 结果
【发布时间】:2012-03-12 23:57:27
【问题描述】:

在下面的代码中,我必须在每次迭代中重复使用 Active Pattern 结果三次。即

match tree.Parent, postion with

我发现我可以保存活动模式结果。即

let pos = ((|Root|Nil|Single|First|Inner|Last|Unknown|) (tree.Parent, position)) 

我不知道是否可以在匹配语句中使用活动模式结果。即

match pos with
| ??? -> printf "("

问题是可以在匹配语句中使用保存的活动模式结果吗?

如果是这样,怎么做?如果不是,则需要对其进行解释,以使其在逻辑上有意义。

可能为什么不的示例。即语言规范,语法糖, 不应允许绑定活动模式结果,ExprItems 与 PatItems

我查看了 F# 2.0 语言规范(2010 年 4 月) http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/spec.html#_Toc270597500

但我没有发现任何可以确认答案的东西。

编辑

如果我将代码更改为

    let pos = (|Root|Nil|Single|First|Inner|Last|Unknown|) (tree.Parent, position)  
    match pos with                                                                
    | Choice1Of7 (tree.Parent, position) -> printf "("                                                          
    | _    -> ()

Choice1Of7 之后出现 (tree.Parent, position) 的以下错误:

这个表达式应该有单位类型,但这里有类型'a *'b

正如布赖恩建议的那样

    match pos with                                                                
    | Choice1Of7 () -> printf "("                                                          
    | _    -> ()    

结束编辑

注意:我在下面尝试了这个代码,但我确实找到了一个更好的算法来解决它。

// An F# function to print a CommonTree as an s-expression
// 
// Note: Because the CommonTree data structure was created allowing null values,
// the null value has to be handled.
// 
let commonTreeToSExpression100 (tree : BaseTree) =
    // Define Active Pattern to create new view of node, i.e. BaseTree
    // for position in list instead of content.
    // Note: The name of the active pattern function    is "|Root|Nil|Single|First|Inner|Last|Unknown|"
    let (|Root|Nil|Single|First|Inner|Last|Unknown|) (tree : ITree , position) =
        let parent = tree :?> BaseTree
        match parent with
        | null -> Root
        | _ ->
            let list = parent.Children
            match obj.ReferenceEquals(list,null) with
            | true -> Nil  // This should never happen.
            | false ->
                let count = list.Count
                // TODO: Handle count = 0
                if (count = 1) then Single
                elif (count > 1) && (position = 0) then First
                elif (count > 1) && (position = count - 1) then Last 
                elif (count > 1) && (0 < position) && (position < count - 1) then Inner
                else Unknown  // This should never happen.

    // Define walk/print function
    let rec printTree (tree : BaseTree) (position) =

        // Start an s-expression
        match tree.Parent, position with
        | Root | Single | First -> printf "("
        | _                     -> ()

        // Note: Can save the result of an active pattern which is type Choice<uint,uint,uint,uint,uint,uint,uint>. 
        // The question is can the saved active pattern result be used in a match statement? 
        // If so, how? If not, need to explain it so that it logicaly makes sense. 
        // Give examples of possibly why not. i.e. Language Specification, syntactic sugar,
        // should not have allowed result to be bound, not in symbol table but other table.
        //let pos = ((|Root|Nil|Single|First|Inner|Last|Unknown|) (tree.Parent, position))  // This works / is allowed
        //    match pos with                                                                
        //    | ???  -> printf "("                                                          // Can this work? What should ??? be?
        //    | _    -> ()

        // Visit the node
        printf "%s" tree.Text    

        // Space out the values
        match tree.Parent, position with
        | Root | First | Inner -> printf " " 
        | _                    -> ()

        // Process the children
        // Note: BaseTree holds the ChildIndex, if this property was not available
        // then the use of Seq.iter whould have to be changed for a mechanism that
        // would allow the calculation of the child index as the list is processed.
        match tree.Children with
        | null -> ()
        | _    -> 
            tree.Children |> Seq.iter (fun x -> printTree (x :?> BaseTree) x.ChildIndex)
            printf " "

        // End an s-expression
        match tree.Parent, position with
        | Root | Single | Last -> printf ")" 
        | _                    -> ()

    // Call the walk/print function
    printTree tree 0

    // Since s-experssions print as single line, 
    // print a newline so that what is printed after this
    // is not on the same line as this s-expression.
    printfn ""

【问题讨论】:

    标签: f# active-pattern


    【解决方案1】:

    它不是特别优雅,但您可以使用用于表示活动模式的底层可区分联合。具有 N 个选项的活动模式的结果使用类型 Choice&lt;'T1, .., 'Tn&gt; 表示,该类型具有成员 Choice1OfN .. ChoiceNOfN

    这是一个简单的例子,只有三种情况:

    let (|Pos|Neg|Zero|) n = 
      if n < 0 then Neg (-n)
      elif n = 0 then Zero
      else Pos n
    
    let res = (|Pos|Neg|Zero|) 10
    
    match res with
    | Choice1Of3 n -> sprintf "pos %d" n
    | Choice2Of3 n -> sprintf "neg %d" n
    | Choice3Of3 () -> "zero"
    

    实际上,我可能不会使用这种方法,但我会定义一个自定义的可区分联合:

    type Number = Pos of int | Neg of int | Zero
    
    let convertNumber n = 
      if n < 0 then Neg (-n)
      elif n = 0 then Zero
      else Pos n
    
    let res = convertNumber 10
    
    match res with
    | Pos n -> sprintf "pos %d" n
    | Neg n -> sprintf "neg %d" n
    | Zero -> "zero"
    

    这需要显式定义可区分联合,但它使代码更具可读性。

    【讨论】:

    • 你想要例如| Choice1Of7 () -&gt; printf "("。你在创建pos时已经传递了这两个参数,现在你只是匹配结果携带的数据。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多