我在使用以下FSharp / F#代码时遇到了一些麻烦:
module File1
let api a =
printf ("VALUE = %A") a
let router ops =
[|
api (ops (fun (list, _) -> list()))
api (ops (fun (_, get) -> get 1))
|]
let withContext ops handler =
let context = "CONTEXT"
handler (ops context)
let operations context =
printf ("CONTEXT = %s") context
let list () = [|1;2;3|]
let get id = "Test"
(list, get)
let setup() =
let ops = withContext operations
router ops
导致以下错误
Results in the following compation error
Error 1 Type mismatch. Expecting a
((unit -> int []) * (int -> int []) -> int []) -> 'a
but given a
((unit -> int []) * (int -> string) -> 'b) -> 'b
The type 'int []' does not match the type 'string'
我知道问题是ops函数已被绑定返回一个int []但我希望能够返回一个字符串。
我认为我错过了一些通用声明的技巧,但是经过几个小时的代码移动后,我似乎无法解决这个问题。
(我已经简化了代码以突出我的问题)
答案 0 :(得分:2)
错误是因为ops
需要在编译时解析其handler
的返回类型,并且您希望根据某些运行时逻辑返回不同的类型。
它基本上相当于:
let fun1 switch arg2 arg3 =
if switch then
arg2
else
arg3
你想以这种方式运行它:
fun1 true 1 "string"
当然,arg2和arg3需要具有相同的类型,因此它不会起作用
你可以做的是运行" api"函数处理程序结果,在返回之前(所以它总是相同的类型 - 单位)。
let router ops =
[|
ops (fun (list, _) -> api <| list()))
ops (fun (_, get) -> api <| get 1))
|]
或者,你可以返回有区别的联合类型的对象(那么在api函数中你需要更多的逻辑)。
(从技术上讲,您也可以返回obj
)。
<强>加成强>
您不需要在router
函数中返回单位数组,返回一个单位就可以了:
let router ops =
ops (fun (list, _) -> api <| list()))
ops (fun (_, get) -> api <| get 1))
通过这种方式,setup
函数也会返回unit
,您无需在结果上运行ignore
就可以运行它来摆脱This expression should have type 'unit', but has type 'unit[]'
警告。
答案 1 :(得分:1)
您的代码很难理解,但我认为基本问题是您希望withContext
具有“等级2”类型(以便对类型变量'b
进行通用量化可以在应用第一个参数后发生)。在F#中,这可以通过使用泛型方法创建一个新类型并使用它来实现:
let api a =
printf ("VALUE = %A") a
type Handler<'a> = abstract Handle<'b> : f:('a->'b) -> 'b
let router (ops:Handler<_>) =
[|
api (ops.Handle (fun (list, _) -> list()))
api (ops.Handle (fun (_, get) -> get 1))
|]
let withContext ops =
let context = "CONTEXT"
{ new Handler<_> with member __.Handle f = f (ops context) }
let operations context =
printf ("CONTEXT = %s") context
let list () = [|1;2;3|]
let get id = "Test"
(list, get)
let setup() =
let ops = withContext operations
router ops