2015-05-02 4 views
1

Я хочу написать функцию, которая будет принимать произвольное число (curried) аргументов и просто распечатать их (или выполнить с ними другое неуказанное действие). Вот что я придумал:Функция с произвольным числом аргументов в F #

let print arg = 
    let rec print args arg = 
     if not (FSharpType.IsFunction(typeof<'t>)) then 
      printfn "%A" args 
      Unchecked.defaultof<'t> 
     else 
      print (box arg::args) 
    print [] 

Когда я пытаюсь скомпилировать это я получаю сообщение об ошибке The resulting type would be infinite when unifying ''t' and ''a -> 't.

Я знаю, что могу просто передать аргументы в виде списка, но я пытаюсь разработать API, где это будет полезной идиомой.

Есть ли какой-нибудь умный трюк компилятора, чтобы сделать такую ​​функцию возможной в F # или это потерянная причина?

+3

Есть несколько способов, чтобы закодировать VARIADIC функции в F #, но компилятор трюк действительно действительно сложный. См. Это [ответ] (http://stackoverflow.com/questions/28243963/how-to-write-a-variadic-functios-in-f-emulating-a-similar-haskell-solution) – Gustavo

+0

ну глупый я - явное обходное решение собирает все интересные типы ввода в ADT и просто использует список по этому типу. Я думаю, – Carsten

+0

Спасибо Gustavo, этот ответ делает то, что я хотел. Я голосую, чтобы закрыть это как дубликат. Я, вероятно, должен был найти больше, прежде чем спрашивать, но был на самом деле дрянной связи, когда я спросил об этом. :-) – luksan

ответ

2

кажется, что две ветви внутреннего print хотят возвращать различные типа: «тогда» часть хочет вернуть 't, но «еще» часть хочет вернуться 'a -> 't, где 't обязательно одинаковы в обеих ветвях , То есть ваша функция пытается вернуть либо свой собственный тип возврата, либо функцию из другого типа в свой собственный тип возврата. Такой комбинированный тип возврата, действительно, будет бесконечным, что полностью соответствует тому, что вы намереваетесь сделать, а именно, создать функцию с бесконечным числом аргументов. Хотя я не знаю, как официально доказать это, я бы сказал, что это действительно невозможно.

Если ваша цель - просто создать список значений в штучной упаковке, вы можете уйти с определением нескольких инфиксных операторов.

let (<+>) a b = a @ [(box b)] 
let (<&>) a b = [(box a); (box b)] 

let xs = 5 <&> "abc" <+> 3.0 <+> None <+> true 
>> val xs : obj list = [5; "abc"; 3.0; null; true] 

В качестве альтернативы, с тщательно подобранным оператором старшинством, вы можете применить функцию (но тогда вам нужен терминатор):

let (^>) a b = (box a)::b 
let (<&>) f xs = f xs 
let print xs = sprintf "%A" xs 

let xs = print <&> 5 ^> "abc" ^> 3.0 ^> None ^> true ^> [] 
>> val xs : string = "[5; "abc"; 3.0; null; true]" 
Смежные вопросы