Вы получаете сообщение об ошибке
Error: operator and operand do not agree [overload conflict]
operator domain: [int ty] * ([* ty] * [* ty] -> [int ty] -> [int ty])
operand: [int ty] * ([* ty] * [* ty] -> [* ty])
in expression:
list_cata (1,(fn (<pat>,<pat>) => <exp> * <exp>))
из-за строки
val prod = list_cata (1, fn (x,y) => x*y)
В частности, второй элемент кортежа, который вы передаете, говорит свободно, введите [* ty] * [* ty] -> [* ty]
. Напротив, вы ожидаете тип, который является экземпляром 'a -> 'b -> 'b
здесь. Таким образом, это происходит потому, что вы используете некритическую функцию, где вы хотите карри.
Предположим, тогда мы изменим на
type ('a, 'b) List_alg = 'b * ('a -> 'b -> 'b)
fun list_cata (a, f) List_alg: 'a list -> 'b =
let
fun cata (xs: 'a list) : 'b =
case xs of
[] => a
| x::xs => f x (cata xs)
in
cata
end
fun curry f a b = f (a, b)
val prod = list_cata (1, curry op*) (* like ( * ) in haskell *)
Если вы сделаете это, вы получите довольно странный тип для prod
, вероятно, не совсем то, что вы хотите. Я не совсем понимаю, как здесь работает вывод типов, хотя кто-то с большим опытом, чем я, мог бы прокомментировать, но, насколько я понимаю, у вас возникла проблема, связанная с тем, что вы хотите быть полиморфной c функцией внутри не -экспансивное выражение (выражение let
) и, таким образом, вызывает ограничение значения SML .
Я думаю, что вы можете еще больше упростить свой код, просто сопоставив шаблон в списке, вместо привязки fun
в let
, например,
fun ('a, 'b) list_cata (f : 'a -> 'b -> 'b) (z : 'b) ([ ] : 'a list) : 'b = z
| list_cata f z (x::xs) = f x (list_cata f z xs)
fun curry f a b = f (a, b)
val prod = list_cata (curry op*) 1