【问题标题】:F# a function as an argument in a match functionF#将函数作为匹配函数中的参数
【发布时间】:2017-03-29 04:02:29
【问题描述】:

我制作了一个函数,它接受一个列表和一个列表列表并返回一个新的列表列表。

let rec calculator list SS =
  match (List.item(0) SS) with
  |[] -> []
  |_ -> match (validate list (List.item(0) SS)) with
        |(validate theCode list) -> List.append [(List.item(0) SS)] (calculator list (SS.[1..])) 
        |_ -> (calculator list (SS.[1..]))

validate 是一个返回两个元组整数的函数。示例 (1,1)

list 是四个整数的列表

SS 是一个包含四个整数的列表

theCode 是四个整数的列表

我收到错误“模式鉴别器'验证'未定义。”

也许这是一个愚蠢的问题,但我仍然不知道答案。

是否不允许在匹配表达式中使用函数作为参数。还是这里发生了完全不同的事情?

据我所知,这两个验证函数将返回两个元组整数,因此应该能够匹配。

【问题讨论】:

  • 我认为你想要一个活动模式
  • "validate 是一个返回两个元组整数的函数。" 假设该函数验证某个输入,当输入有效时它返回什么?输入无效时返回什么?
  • 要编译它,请将|(validate theCode list) -> 替换为| x when x = (validate theCode list) ->。但正如@JohnPalmer 暗示的那样,这很丑陋——即使是if..else 在这里也会更干净。
  • 它永远不会返回无效的东西。它总是会返回有效的东西。它至少会返回 (0,0) ,我告诉它删除列表列表中的所有元素
  • 好的,这里首选的方法是什么?我不太明白这种活动模式在这里有什么用处。

标签: list f# match discriminator guard-clause


【解决方案1】:

如果您的问题是如何编译它,那么您只需要稍作改动——函数调用本身并不是一种模式,因此您需要绑定到一个值并使用when guard

let rec calculator list SS =
    match (List.item(0) SS) with
    | [] -> []
    | _  ->
        match (validate list (List.item(0) SS)) with
//        vvvvvvvvvv
        | x when x = (validate theCode list) ->
            List.append [(List.item(0) SS)] (calculator list (SS.[1..]))
        | _ -> (calculator list (SS.[1..]))

但是,如果您的问题确实是“首选方法是什么”,那么虽然这对于本网站 (IMO) 来说过于主观,但我会将其作为我认为理想可读的选项提交对于这个逻辑:

let rec calculator list (h::t) =
    if List.isEmpty h then h
    elif validate list h = validate theCode list then h::(calculator list t)
    else calculator list t

(假设SS 是一个F# 列表而不是System.Collections.Generic.List。)

【讨论】:

  • 请注意:使用h :: calculator list t 将单个元素添加到列表中要比构造一个包含一个元素的新列表来添加列表更常见。
  • @JakeLishman:确实!我专注于从match 切换,并没有彻底考虑其余部分(显然)。已编辑,谢谢。
【解决方案2】:

这实际上不是对如何实现when 守卫问题的答案,因为@ildjarn answered 是为你准备的。

我认为图书馆功能实际上会更好地为您服务。您尝试做的似乎是过滤掉未通过验证的元素,而且还要在第一个空元素上停止。如果你能保证你肯定想遍历SS 的每个元素,你可以简单地做

let calculator list = List.filter (fun s -> validate list s = validate theCode list)

如果你必须在空元素处停止,你可以定义一个在第一个空元素处切割列表的函数,类似于

let upToElement element list =
    let rec loop acc = function
        | [] -> List.rev acc
        | h :: t when h = element -> List.rev acc
        | h :: t -> loop (h :: acc) t
    loop [] list

那你就可以了

let calculator list =
    upToElement [] >> List.filter (fun s -> validate list s = validate theCode list)

【讨论】:

  • 非常感谢!我的意图只是过滤掉任何未通过验证的元素。所以我一定会调查你的 List.filter 解决方案!
猜你喜欢
  • 2015-07-12
  • 2014-03-15
  • 1970-01-01
  • 2021-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-22
相关资源
最近更新 更多