简体   繁体   中英

Anything like Java's static imports in F#?

Coming from Haskell, I'd like to know if there is a way to avoid having to write the full List.map every time I want to use a map .

Is there anything such as Java's static imports, so that I can only write map ?

To recap:

I currently have to write:

List.map (fun -> 3*x) [1..10]

yet, I'd like to be able to write

map (fun -> 3*x) [1..10]

Thanks

In Java, given a class mypackage.MyClass you can "statically import" all static members within that class using the declaration import static mypackage.MyClass.* . In F#, given the module MyNamespace.MyModule you can similarly make all functions within that module available without qualification using the declaration open MyNamespace.MyModule . But as Daniel pointed out, certain module are marked with the RequireQualifiedAccess attribute which forbids this.

However, you can still alias specific functions within a module similar to how you can statically import specific static members of a class in Java. For example, in Java, you can do something like static import mypackage.MyClass.myMethod and in F# you can do let map = List.map .

Except, there is a good reason collection modules like List , Seq , and Array all require qualified access: they all have a similar set of functions which only act on their types and F# uses this information for its type inference. I'm not sure of the details but Haskell has some feature in its type system which allows map , for example, to be used on several different types without breaking type inference. Note that Seq is a bit special though in F# (and .NET), since it works on all types implementing the interface IEnumerable<'a> including lists and arrays. So you could alias let map = Seq.map and be able to work with map on all those collection types but you would lose features of those concrete implementations since IEnumerable<'a> is the lowest common denominator among them.

So in the end, in F#, the best thing to do is just use the fully qualified map functions in each collection module. It's a small price to pay for the type inference you get in return (I sometimes wonder if I save in typing through type inference what I lose having to qualify all those collection functions, but I believe you win in the end through type inference savings especially when considering complex generic signatures and perhaps more importantly having to reason through all those type calculations).

One more option for saving key strokes is through module aliases. You can do something like module L = List . I wouldn't do this for short, common module names like List , but I might do it for ResizeArray or perhaps my own sometimes long-winded module names.

You can do something like:

let map = List.map
map (fun x -> 3*x) [1..10]

Usually, you can do exactly what you want--use a function without qualification--by using open TheModuleContainingTheFunction . The exceptions are modules marked with the RequireQualifiedAccess attribute. List , Seq , and Array have this attribute.

I suspect these require qualification because they have many functions with the same names ( map , iter , etc) and there is a polymorphic relationship between the types they deal with, ie, Array and List may be treated as Seq , which would seem to make many unqualified function calls ambiguous.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM