我正在尝试用F#设计一个库.该库应该对F#和C#都很友好.
这就是我被困住的地方.我可以使它F#友好,或者我可以使它C#友好,但问题是如何使它友好的两者.
这是一个例子.想象一下,我在F#中有以下功能:
let compose (f: 'T -> 'TResult) (a : 'TResult -> unit) = f >> a
Run Code Online (Sandbox Code Playgroud)
这完全可以从F#中使用:
let useComposeInFsharp() =
let composite = compose (fun item -> item.ToString) (fun item -> printfn "%A" item)
composite "foo"
composite "bar"
Run Code Online (Sandbox Code Playgroud)
在C#中,该compose函数具有以下签名:
FSharpFunc<T, Unit> compose<T, TResult>(FSharpFunc<T, TResult> f, FSharpFunc<TResult, Unit> a);
Run Code Online (Sandbox Code Playgroud)
但当然我不想FSharpFunc签名,我想要的是Func,Action而是像这样:
Action<T> compose2<T, TResult>(Func<T, TResult> f, Action<TResult> a);
Run Code Online (Sandbox Code Playgroud)
为此,我可以创建这样的compose2函数:
let compose2 (f: Func<'T, 'TResult>) (a : Action<'TResult> ) …Run Code Online (Sandbox Code Playgroud) 我一直认为,在F#访问控制的关键字(public,private,internal)在,因为他们在C#中做同样的工作方式.确实从MSDN文档访问控制(F#):
- public表示所有呼叫者都可以访问该实体.
- internal表示只能从同一个程序集访问该实体.
- private表示只能从封闭类型或模块访问实体.
这似乎与我的假设非常一致,并且在SO提供的主题上也有多个答案.
但是,当我使用Reflector调入已编译的代码时,我发现所有声明为private的成员实际上都被编译为内部(程序集可见性),这与文档不匹配.
为了避免任何疑问,我创建了一个小测试来确认这一点.
F#代码:
// Make internals visible to other assemblies
[<assembly:InternalsVisibleTo("MyCSharpAssembly")>]
// OK. Expect: "internal static class PrivateModule" in C#
module private PrivateModule =
// FAIL. Expect: "private static void privateStaticMethod()" in C#
let private privateStaticMethod() = ignore()
// OK. Expect: "internal class InternalClass" in C#
type private InternalClass() =
// FAIL. Expect: "private int privateInstanceField" in C#
let privateInstanceField …Run Code Online (Sandbox Code Playgroud) 我看起来可能需要开始一些跨平台项目,其中一部分必须用C或C++完成(尚未确定,因此问题是关于它们两者).我将主要处理基于文本的东西和字符串.
C/C++将具有可从更高级别的平台相关代码调用的API.
我的问题是:建议使用什么类型的字符串,特别是在声明公共接口时?有没有推荐的标准技术?有什么可以避免的吗?
我几乎没有编写C或C++代码的经验,甚至那都是在Windows上,所以没有什么比这更像是跨平台了.所以我真正想要的是让某些东西能够让我以正确的方式行事,避免做出愚蠢的事情,这些事情必将引起很多痛苦.
编辑1:提供有关预期用途的更多上下文.API将被以下消费者使用:
通过NSString和朋友在iPhone/iPad/Mac上实现目标C. API可以静态链接,因此无需担心.so .dll问题.
Java通过JNI在Android和其他Java平台上运行
.NET通过p/invoke从托管C#代码或本机静态链接(如果使用C++/CLI).
关于在这种情况下以某种方式/某处使用lua有一些想法.不知道这是否与任何事情有关.
我偶然发现了这一点,我有点困惑.
我有一个开箱即用的VS 2010 F#项目,所有默认设置都针对.NET 4.0.
F#代码是这样的:
let test(a:int, b:int, c:int) = min a (min b c)
Run Code Online (Sandbox Code Playgroud)
当我编译它以供发布时,生成的IL包含一些NOP
分散的奇怪指令.像这样:
为此生成的IL(具有所有默认设置):
.method public static int32 test(int32 a,
int32 b,
int32 c) cil managed
{
// Code size 20 (0x14)
.maxstack 4
.locals init ([0] int32 V_0)
// HERE
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: bge.s IL_0009
IL_0005: ldarg.1
// HERE
IL_0006: nop
IL_0007: br.s IL_000b
IL_0009: ldarg.2
// HERE
IL_000a: nop
IL_000b: stloc.0
IL_000c: ldarg.0
IL_000d: ldloc.0
IL_000e: bge.s IL_0012 …Run Code Online (Sandbox Code Playgroud) 这是一个假设的场景.
我有非常多的用户名(比如10,000,000,000,000,000,000,000.是的,我们处于星际时代:)).每个用户都有自己的数据库.我需要遍历用户列表并对每个数据库执行一些SQL并打印结果.
因为我学会了函数式编程的优点,并且因为我处理了如此多的用户,所以我决定使用F#和纯序列(也就是IEnumerable)来实现它.我走了
// gets the list of user names
let users() : seq<string> = ...
// maps user name to the SqlConnection
let mapUsersToConnections (users: seq<string>) : seq<SqlConnection> = ...
// executes some sql against the given connection and returns some result
let mapConnectionToResult (conn) : seq<string> = ...
// print the result
let print (result) : unit = ...
// and here is the main program
users()
|> mapUsersToConnections
|> Seq.map mapConnectionToResult
|> Seq.iter print
Run Code Online (Sandbox Code Playgroud)
美丽?优雅?绝对.
但! 谁和什么时候处置SqlConnections? …
假设我有一个功能,它做了一些相当复杂的功能,它是在子功能的帮助下实现的.为了使事情更容易,而不是元组,我想使用一些私有的中间结构来实现这个功能.
我不希望这些结构的声明泄漏到外面.所以我想要这样的东西:
let someComplexFun p =
type SomeRecord = {i:int; x:int; y:int;}
type SomeOtherRecord = {...}
let innerFunctionA (x:SomeRecord) = ...
let innerFunctionB (x:SomeOtherRecord) = ...
...
Run Code Online (Sandbox Code Playgroud)
我尝试过但当然编译器不允许我这样做.我查看了文档,我无法在任何地方看到类型必须在模块级别声明.
例如,在LISP中,它似乎完全合法,例如:
(defun foo (when)
(declare (type (member :now :later) when)) ; Type declaration is illustrative and in this case optional.
(ecase when
(:now (something))
(:later (something-else))))
Run Code Online (Sandbox Code Playgroud)
那么,我错过了什么吗?如果F#完全可以吗?
我在宣告降序的过程中遇到了一些麻烦int64.
我想要的是这个:
seq{0L..-5L..-10L};;
Run Code Online (Sandbox Code Playgroud)
但是,我收到一个错误:
seq{0L..-5L..-10L};;
---^^^^^^^^^^^^^^^
stdin(5,4): error FS0739: Invalid object, sequence or record expression
Run Code Online (Sandbox Code Playgroud)
有趣的是,它适用于普通int:
> seq{0..-5..-10};;
val it : seq<int> = seq [0; -5; -10]
Run Code Online (Sandbox Code Playgroud)
更有趣的是,如果我在..它之间放置空格,它也开始使用int64:
> seq{0L .. -5L .. -10L};;
val it : seq<int64> = seq [0L; -5L; -10L]
Run Code Online (Sandbox Code Playgroud)
有人可以解释为什么编译器会进入扭曲状态seq{0L..-5L..-10L}吗?