возможно ли развернуть цикл в F # (в .net вообще)?

#.net #f#

#.net #f#

Вопрос:

итак, что я подразумеваю под разверткой цикла, это

 Write "Hello" |> Repeat 5
  

->>>

 Write "Hello"
Write "Hello"
Write "Hello"
Write "Hello"
Write "Hello"
  

насколько я знаю, это некоторая оптимизация, и мне просто интересно, возможно ли это в .NET

Кстати, просто почему я должен использовать for i в [0 ..4] do … если я на самом деле не это [0 ..4] и мне это действительно не нужно, я …

Комментарии:

1. вы хотите ввести приведенное выше и получить результат ниже в своем коде?

2. Такой вещи не существует. Попробуйте «от 1 до n».

3. IL не предназначен для включения каких-либо оптимизаций. Оптимизация выполняется при переводе с IL на native в JIT.

4. согласно последним комментариям — Похоже, я не могу этого сделать без использования for — это печально. У меня еще один вопрос не по теме: почему вы отвечаете в виде комментариев?

5. @nCdy повторно «почему вы задаете вопросы в комментариях» — потому что на самом деле это не ответы на вопрос… такие вещи, как отступы, запросы на дополнительную информацию и т.д., Лучше всего представлять в виде комментариев.

Ответ №1:

Язык F # напрямую не поддерживает эту форму метапрограммирования. То, о чем вы просите, обычно называется многоступенчатым программированием, и существуют языки на основе ML, которые его поддерживают (найдите, например, MetaML). На этих языках вы можете манипулировать скомпилированным кодом и (например) разворачивать циклы.

Ограниченная форма этого может быть выполнена в F # с использованием кавычек. Однако это не очень практично, потому что компилятор цитат F # генерирует более медленный код (так что это определенно не работает как оптимизация).

Однако, просто из любопытства, вот как этого добиться, используя цитаты и компилятор цитат из F # PowerPack:

 #r @"FSharp.PowerPack.Linq.dll"
open Microsoft.FSharp.Linq.QuotationEvaluation

// Generate quotation that contains 5 prints followed by expression that returns unit
let unrolled = [ 1 .. 5 ] |> List.fold (fun expr _ -> 
    <@ printfn "Hello"; %expr @>) <@ () @>

// Compile the function once amp; run it two times
let f = unrolled.Compile()
f()
f()
  

… как я уже упоминал, это бесполезно в качестве оптимизации, потому что Compile метод создает медленный код, но он полезен в некоторых других сценариях.

Комментарии:

1. Действительно ли метод компиляции создает медленный код, или вы хотели сказать, что метод компиляции сам по себе медленный?

2. @Robert: На самом деле это приводит к замедлению кода. Он использует деревья выражений из C # 3, поэтому использует довольно ограниченный целевой язык. Например, printf "a"; printf "b" компилируется как (в синтаксисе C #) Helpers.Sequence(() => printf("a"), () => printf "b");

Ответ №2:

Вы можете написать for _ in 0..4 , чтобы указать, что вам не нужно значение переменной цикла.

Выполнение чего-то вроде развертывания цикла на уровне языка F # потребует поддержки макросов. В таких языках, как Lisp или Clojure, вы могли бы это сделать. Но обычно лучше позволить компилятору или среде выполнения беспокоиться об этом.

На уровне IL вы могли бы реализовать такие вещи, как развертывание цикла, используя классы System.Reflection.Emit пространства имен (или используя для этого библиотеку, подобную Cecil).

Комментарии:

1. интересно, реально ли это для макросов Nemerle

Ответ №3:

Вы не можете обойтись без ‘for’, но вы можете абстрагировать его в своей собственной функции

 let Write msg = 
    fun () -> printfn msg

let Repeat n f = 
    for _ in 1..n do
        f() 

Write "Hello" |> Repeat  5