Кортеж определяется как (exp1, exp2, ..., expn), например (1, «2», «3»).
Я не вижу этот шаблон в вашем коде.
Если вы используете (exp1 exp2), это означает применение функции (примените exp2 в качестве первого аргумента к функции exp1).
Ошибка, которую вы видите в своем коде, заключается в том, что вы определили Conj как функцию, принимающую функцию в качестве первого параметра, и передали строку («a») вместо функции.
Если ваш вопрос состоит в том, как разделить кортеж по голове и хвосту, вы можете использовать динамический подход, который только что объяснил Томас, он будет работать для любого n-кортежа, но вы потеряете информацию о типе.
В противном случае решение для сильного типа просто основано на сопоставлении с образцом:
let splitTuple (a,b,c) = (a,(b,c))
// Usage
let (head,tail) = splitTuple (1,"2",'3')
И если вы хотите, чтобы это работало для n-кортежей, вам нужно определить одну перегрузку для каждого n:
type TupleSplitter =
static member splitTuple (a,b,c) = (a,(b,c))
static member splitTuple (a,b,c,d) = (a,(b,c,d))
static member splitTuple (a,b,c,d,e) = (a,(b,c,d,e))
// ... more overloads, as much as you need
// Usage
let (head,tail) = TupleSplitter.splitTuple (1,"2",'3',4.0)
// val tail : string * char * float = ("2", '3', 4.0)
// val head : int = 1