在F#中扩展Core.Option模块

Ser*_*kov 6 f#

我想扩展一个现有的"核心"模块,例如Core.Option:

module Microsoft.FSharp.Core.Option

    let filter predicate op =
        match op with
        | Some(v) -> if predicate(v) then Some(v) else None
        | None -> None
Run Code Online (Sandbox Code Playgroud)

(我知道bind功能,但我认为filter在某些情况下选项的方法更方便).

但不幸的是,我无法在filter没有明确打开Microsoft.FSharp.Core命名空间的情况下使用方法:

// Commenting following line will break the code!
open Microsoft.FSharp.Core

let v1 = Some 42
let v2 = v1 |> Option.filter (fun v -> v > 40)

printfn "v2 is: %A" v2
Run Code Online (Sandbox Code Playgroud)

在大多数情况下,我们不能在不打开适当的命名空间的情 F#编译器自动"打开"一些预定义(核心)命名空间(如Microsoft.FSharp.Core),这不会从"模块扩展"引入范围方法,我们仍然应该手动打开核心命名空间.

我的问题是:有没有解决方法?

或者扩展"核心"模块的最佳方法是在自定义命名空间中创建此类扩展并手动打开此命名空间?

// Lets custom Option module in our custom namespace
module CustomNamespace.Option

    let filter predicate op = ...

// On the client side lets open our custom namespace.
// After that we can use both Option modules simultaneously!
open CustomNamespace

let v1 = Some 42
let b = 
    v1 |> Option.filter (fun v -> v > 40) // using CustomNamespace.Option
    |> Option.isSome // using Microsoft.FSharp.Core.Option
Run Code Online (Sandbox Code Playgroud)

Tah*_*aha 5

为了扩展一个 F# 模块,创建另一个同名的模块:

module Option =

    let filter predicate op =
        match op with
        | Some v  -> match predicate v with true -> Some v | false -> None
        | None    -> None


let v1 = Some 42
let v2 = v1 |> Option.filter (fun v -> v > 40)

printfn "v2 is: %A" v2
Run Code Online (Sandbox Code Playgroud)

  • 您不必在全局命名空间中执行此操作,只要“打开”包含的命名空间即可。就是这样完成的。 (4认同)

Rob*_*sen 5

如果将AutoOpen属性添加到模块中会有帮助吗?

[<AutoOpen>]
module Microsoft.FSharp.Core.Option

    let filter predicate op =
        match op with
        | Some(v) -> if predicate(v) then Some(v) else None
        | None -> None
Run Code Online (Sandbox Code Playgroud)

编辑

这有效,但仅适用于装配边框.它在同一个程序集中不起作用:

namespace Microsoft.FSharp.Core
module Option =
    let filter predicate op =
        match op with
        | Some(v) -> if predicate(v) then Some(v) else None
        | None -> None

[<assembly:AutoOpen("Microsoft.FSharp.Core")>]
do ()
Run Code Online (Sandbox Code Playgroud)

要从另一个程序集调用它:

[<EntryPoint>]
let main args = 
    let f () = Some "" |> Option.filter (fun f -> true)
    Console.WriteLine("Hello world!")
    0
Run Code Online (Sandbox Code Playgroud)


t0y*_*yv0 5

对于生产代码,我会做Taha的答案所建议的:创建自己的模块并根据需要打开/别名.你作为程序员的大部分时间都将花在阅读代码上.阅读F#代码可能会非常令人沮丧,因为不清楚方法的来源.

话虽这么说,我惊讶地发现这有效:

namespace Microsoft.FSharp.Core

module Option =

    let filter predicate op =
        match op with
        | Some(v) -> if predicate(v) then Some(v) else None
        | None -> None

namespace USERCODE

module Option = Microsoft.FSharp.Core.Option

module M =

    let test () =
        Some 1
        |> Option.filter (fun x -> x > 0)
        |> Option.map (fun x -> x + 1)
Run Code Online (Sandbox Code Playgroud)

它不会消除在文件头部写入内容的需要,但它确实需要打开命名空间.不相关,Microsoft.FSharp.Core因为默认情况下它总是打开,但对其他命名空间很有帮助.