how would I constrain to non-function?

梦想与她 提交于 2020-02-04 01:24:09

问题


I'm working on code that abstracts away System.Data.IDbConnection and its siblings.

target code

let inline runWithConnection connector f = 
        match connector with
        | ICon con -> f con
        | CString cs -> 
            use conn = new SqlConnection(cs)
            openConnection conn
            f conn

I can see that type constraints compile and run, but constraining to object doesn't have the intended effect. I want to constrain to an object or value that is not a function that needs more inputs to return something. Alternatively write this in such a way that if it does return a function the possibly created connection isn't closed until f is done with it.

let inline runWithConnection connector (f:_ -> 't when 't :> obj) = 
        match connector with
        | ICon con -> f con
        | CString cs -> 
            use conn = new SqlConnection(cs)
            openConnection conn
            f conn

It seems you can say 't : not struct but you can't say 't: not delegate

I thought about doing f.GetType() but then I have no idea which type properties like .IsClass, .IsAbstract, .IsValue would be consistent with delegate types as opposed to other simple types. Also that would be run-time instead of compile time, not really improving the situation.


回答1:


I think what you're saying that this doesn't work when you call runWithConnection with a curried f as the connection is disposed after the first partial function is returned.

No generic constraints will solve this as you can't constrain to a type that isn't something i.e. a function. This is the same across F#, C#, Java etc.

You could possibly throw a runtime exception, but I think it's much easier to revisit the pattern you're attempting. I'd ask what you save by having the outer function execute the function it's passed, rather than just returning the generated connection as an IDisposable. This would let the calling function control the scope of the connection, e.g.:

use conn = getConnection myConnector
doSomethingWithConnection conn anotherArg



回答2:


Note that your problem isn't limited to just function return types - there are plenty of "normal" types that problematic, too. Consider if f is (fun conn -> [conn]) - then you're just returning a list, but the connection stored in that list will be closed by the time the function returns. Likewise, you could create a class type ConnectionUser whose constructor takes and stores a connection and whose methods/properties use it, and that wouldn't work as a return type for f for the same reason. So I agree with Tim Rogers that you should try to come up with a cleaner abstraction.

As an aside, I don't think that inline is buying you anything here, so you can probably safely drop it.



来源:https://stackoverflow.com/questions/35462215/how-would-i-constrain-to-non-function

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!