【问题标题】:Applying a function to a custom type in F#将函数应用于 F# 中的自定义类型
【发布时间】:2010-03-12 14:00:44
【问题描述】:

在我学习 F# 的过程中,我遇到了一个我无法解决的问题。我已经定义了一个自定义类型:

type BinTree = 
  | Node of int * BinTree * BinTree
  | Empty

我做了一个函数,它接受一棵树,遍历它,并将它访问的元素添加到一个列表中,然后返回它:

let rec inOrder tree = 
 seq{
 match tree with
  | Node (data, left, right) ->
   yield! inOrder left
   yield  data;
   yield! inOrder right
  | Empty -> ()
 }
 |> Seq.to_list;

现在我想创建一个函数,类似于这个,它接受一个树和一个函数,遍历它并将一个函数应用于每个节点,然后返回树:

mapInOrder : ('a -> 'b) -> 'a BinTree -> 'b BinTree

这看起来很简单,而且很可能就是这样!但我不确定如何归还树。我试过这个:

let rec mapInOrder f tree = 
 match tree with
 | Node(data, left, right) ->
  mapInOrder f left
  Node(f(data), left, right)
  mapInOrder f right
 | Empty -> ()

但这会返回一个单位。我以前没有使用过自定义类型,所以我可能在那里遗漏了一些东西!

【问题讨论】:

    标签: f# functional-programming


    【解决方案1】:

    试试这个:

    let rec mapInOrder f = function
      | Node(a,l,r) ->
          let newL = mapInOrder f l
          let b = f a
          let newR = mapInOrder f r
          Node(b,newL,newR)
      | Empty -> Empty
    

    如果函数没有副作用,则遍历顺序不重要,您可以改为:

    let rec map f = function
      | Node(a,l,r) -> Node(f a, map f l, map f r)
      | Empty -> Empty
    

    【讨论】:

    • 这行得通,谢谢!在这种情况下,“函数”是关键字还是变量?您在标头中只有一个变量,但您在递归调用中传递了两个参数?
    • 这是一个关键字。这是一个巧妙的捷径,可以实现更简洁的模式匹配——function 内置了模式匹配,let 没有。此代码同时使用两者:它将(使用letmap f 定义为一个单参数函数,其结果也是一个单参数函数(使用function 定义)。最终结果是一个双参数函数。
    • @Frederik - Nathan 很好地解释了这一点,但只是稍微详细说明一下,function 等同于 fun x -> match x with。由于let fn x = ... 也等价于let fn = fun x -> ...,你可以将我定义的第一行改写为let rec mapInOrder f tree = match tree with。希望对您有所帮助。
    • @Frederik Wordenskjold,您可能也对这个问题感兴趣:stackoverflow.com/questions/1839016/…
    【解决方案2】:

    匹配是一个表达式。它返回匹配案例的值。这意味着所有匹配案例必须具有相同的类型。匹配表达式本身就具有该类型。

    在您的第一次尝试中,您的 Empty 子句返回 (),因此具有单元类型,而不是您要查找的树类型。

    由于 mapInOrder 只是返回匹配结果,所以它也采用了单位返回类型。

    Node 子句很好,因为它的返回值是调用 mapInOrder 的结果,所以它也接受了单元类型,并且满足了所有匹配子句具有相同类型的要求。

    kvb 建议的一个关键变化是让 Empty 子句返回树而不是单元。一旦你这样做了,你就会得到指向其他问题的编译器错误和警告。

    您通常可以通过显式编码您想要的类型来解决此类问题,然后查看编译错误和警告出现的位置。

    【讨论】:

      猜你喜欢
      • 2016-11-03
      • 2018-03-03
      • 1970-01-01
      • 2020-05-19
      • 2022-01-02
      • 2020-10-29
      • 2020-12-14
      • 2017-02-27
      • 1970-01-01
      相关资源
      最近更新 更多