【问题标题】:Composing 2 (or n) ('a -> unit) functions with same arg type组合 2 个(或 n)('a -> unit)具有相同 arg 类型的函数
【发布时间】:2014-10-18 14:17:35
【问题描述】:

是否有某种形式的内置/术语我不知道有点但它不同的“组合”两个 'a -> unit 函数来产生一个;例如:

let project event =
    event |> logDirections
    event |> stashDirections
let dispatch (batch:EncodedEventBatch) =
    batch.chooseOfUnion () |> Seq.iter project

可能变成:

let project = logDirections FOLLOWEDBY stashDirections
let dispatch (batch:EncodedEventBatch) =
    batch.chooseOfUnion () |> Seq.iter project

然后:

let dispatch (batch:EncodedEventBatch) =
    batch.chooseOfUnion () |> Seq.iter (logDirections FOLLOWEDBY stashDirections)

我想有人可能会将其与tee 进行比较(正如在FSFFAP's Railway Oriented Programming series 中提到的那样)。

(它需要将相同的 arg 传递给两者,并且我正在寻求按顺序运行它们而没有任何异常处理技巧问题等)

(我知道我可以做到let project fs arg = fs |> Seq.iter (fun f -> f arg),但我想知道是否有内置的东西和/或我不知道的某种形式的组合库

【问题讨论】:

    标签: f# action composition side-effects function-composition


    【解决方案1】:

    您可以将一组函数应用于给定数据吗? 例如。你可以定义:

    let apply (arg:'a) (fs:(('a->unit) seq)) = fs |> Seq.iter (fun f -> f arg)
    

    然后你就可以做这样的事情了:

    apply 1 [(fun x -> printfn "%d" (x + 1)); (fun y -> printfn "%d" (y + 2))]
    

    【讨论】:

    • +1 答案没有错,但我应该更明确一点,如何定义助手不是我的问题,我可以避免定义助手。
    【解决方案2】:

    来自 Klark 的 apply 函数是解决问题的最直接的方法。

    如果您想更深入地挖掘并更普遍地理解这个概念,那么您可以说您正在提升顺序组合操作,从处理 values 到处理 函数。

    首先,F# 中的; 构造可以被视为顺序组合运算符。可悲的是,您不能完全将其用作一个,例如(;)(因为它在第二个参数中是特殊且惰性的)但我们可以定义自己的运算符来探索这个想法:

    let ($) a b = a; b
    

    所以,printfn "hi" $ 1 现在是一个副作用操作和一些计算结果为1 的表达式的顺序组合,它与printfn "hi"; 1 做同样的事情。

    下一步是定义一个提升操作,将处理值的二元运算符转换为处理函数的二元运算符:

    let lift op g h = (fun a -> op (g a) (h a))
    

    而不是写例如fun x -> foo x + bar x,你现在可以写lift (+) foo bar。因此,您可以通过一种无点的方式来编写相同的内容 - 只需使用适用于函数的操作。

    现在您可以使用lift 函数和顺序组合运算符来实现您想要的:

    let seq2 a b = lift ($) a b
    let seq3 a b c = lift ($) (lift ($) a b) c
    let seqN l = Seq.reduce (lift ($)) l
    

    seq2seq3 函数仅组成两个操作,而 seqN 与 Klark 的 apply 函数做同样的事情。

    应该说我写这个答案不是因为我认为以这种方式在F#中实现东西很有用,而是正如你提到的面向铁路的编程并要求背后更深层次的概念对此,看看如何用函数式语言组合是很有趣的。

    【讨论】:

    • +1 谢谢 - 我希望你能像那样读懂我的想法。我喜欢这种语言(以及 C# : F# :: Jon Skeet : Tomas Petricek)。一般来说,我不会为在 F# 中定义局部函数来加糖这样的东西而出汗,但似乎应该有一些东西可以解决这个问题。我想我会接受,尽管这并不能解决我对用函数式语言编写副作用函数的愿望:D(说真的,我知道这是一个坏主意,而不是常见的事情)
    猜你喜欢
    • 2018-09-21
    • 1970-01-01
    • 2012-01-10
    • 2022-10-07
    • 1970-01-01
    • 2022-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多