You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

F#自定义二元运算符编译报错:期望支持'-'的类型却得到函数类型

F#自定义运算符相关问题解答

1. 报错原因

你遇到的Expecting a type supporting the operator '-' but given a function type报错是编译器无法正确识别运算符导致的:
定义在ListA<'T>类型内部的.<<<.和.>>>.两个运算符,所有参数都是函数类型,不符合F#对类型内部静态二元运算符的要求:定义在类型内的二元运算符必须至少有一个参数是当前类型的实例。因此编译器不会将这两个运算符纳入ListA的重载解析范围,调用时会尝试把符号拆分为内置运算符解析,拆分后的运算符要求数值类型支持,传入函数就触发了类型不匹配报错。

2. F#自定义二元运算符的正确规范

  • 符号限制:运算符只能由! $ % & * + - . / < = > ? @ ^ | ~范围内的字符组成,不能使用其他特殊字符。
  • 优先级与结合性:运算符的优先级、结合性和首字符对应的内置运算符完全一致,比如*开头的运算符优先级高于+开头的运算符,默认左结合,=类赋值运算符为右结合。
  • 定义位置要求:
    • 运算符至少有一个参数是自定义类型时,可定义为该类型的静态成员,泛型场景下建议标注inline优化类型推导。
    • 运算符所有参数都不是自定义类型时,必须定义为模块级别的let绑定,不能放在某一类型的内部。
  • 命名建议:避免定义过于生僻的运算符组合,降低代码可读性。

3. 运算符定义位置差异的原因

  • .>>=.的第一个参数是ListA<'T>类型实例,满足类型内部运算符的定义要求,调用时只要第一个参数是ListA类型,编译器就能匹配到内部定义的运算符,因此可以正常使用。
  • .-->-.的两个参数都是函数类型,没有参数属于ListA<'T>类型,放在ListA内部定义时不会被编译器纳入重载解析范围,调用时找不到对应运算符,因此必须定义在模块级别才能正常使用。

原问题关联代码

type ListA<'T> = NIL | Cons of 'T * ListA<'T> with
        static member cat (a:ListA<'T>) (b:ListA<'T>) :ListA<'T>=
            match a with
                | NIL -> b
                | Cons (a, tail) -> Cons (a, (ListA<'T>.cat tail b))
        static member join (a:ListA<ListA<'T>>)  =
            match a with
                | NIL -> NIL
                | Cons (a, b) -> ListA<'T>.cat a (ListA<'T>.join b)

        static member fmap (fn: 'T -> 'U) (a:ListA<'T>)  =
                 match a with
                    | NIL -> NIL
                    | Cons (a, tail) -> Cons ((fn a), (ListA<'T>.fmap fn tail))
        
        static member inline (.>>=.)(ma:ListA<'T> , k:'T -> ListA<'U>) =  ListA<'T>.fmap k ma |> ListA<_>.join

        static member inline (.<<<.)(mbc:'B -> ListA<'C> , mab:'T -> ListA<'B>) = (fun x -> (mab x) .>>=. mbc)
        static member inline (.>>>.)(mab:'T -> ListA<'B> , mbc:'B -> ListA<'C>) = (fun x -> (mab x) .>>=. mbc)
        
        static member join2 (a:ListA<_>)  =  a .>>=. id
    
    
let (.-->.)(mab:'T -> ListA<'B>) (mbc:'B -> ListA<'C>) = (fun x -> (mab x) .>>=. mbc)
let (.<--.)(mab:'B -> ListA<'C>) (mbc:'T -> ListA<'B>) = (fun x -> (mbc x) .>>=. mab)
    
let f  = fun x ->  Cons (x, Cons ((x + 1), NIL))    
let g  = fun x ->  Cons (x * 2, NIL)
// NOT Compiling: let fgA = fun x -> (f .<<<. g) 
// NOT Compiling: let fgB = fun x -> (f .>>>. g) 
let fg = fun x -> (f x) .>>=. g
let fg1 = (f .-->. g .-->. g)
let fg2 = (f .<--. g .-->. f)
printfn "%A" (fg1 3)

内容的提问来源于stack exchange,提问作者Marc Engher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 01:15:03