А>Слона-то и не видно. Новое (старое?) — функциональные стримы. А>type А> LazyList<'a> = Cons of ('a*Stream<'a>) | Nil А>and А> Stream<'a> = unit -> LazyList<'a>
Здравствуйте, Аноним, Вы писали:
А>Слона-то и не видно. Новое (старое?) — функциональные стримы. А>type А> LazyList<'a> = Cons of ('a*Stream<'a>) | Nil А>and А> Stream<'a> = unit -> LazyList<'a>
Поскольку F# как и OCaml энергичный язык, для ленивого эффекта используются функции.
Не знаю, как можно сделать ленивый список иначе.
Здравствуйте, achmed, Вы писали:
A>Поскольку F# как и OCaml энергичный язык, для ленивого эффекта используются функции. A>Не знаю, как можно сделать ленивый список иначе.
В OCaml есть и поддержка на уровне языка, ключевое слово lazy
Здравствуйте, FR, Вы писали:
FR>Здравствуйте, achmed, Вы писали:
A>>Поскольку F# как и OCaml энергичный язык, для ленивого эффекта используются функции. A>>Не знаю, как можно сделать ленивый список иначе.
FR>В OCaml есть и поддержка на уровне языка, ключевое слово lazy
Действительно .. забыл совсем .
Интересно, использование lazy дает какое то преимущество в плане использования ресурсов перед простым оборачиванием в функцию?
Здравствуйте, achmed, Вы писали:
FR>>В OCaml есть и поддержка на уровне языка, ключевое слово lazy
A>Действительно .. забыл совсем . A>Интересно, использование lazy дает какое то преимущество в плане использования ресурсов перед простым оборачиванием в функцию?
lazy гарантирует мемоизацию, но опять же, можно эмулировать функциями и ref'ами.
Здравствуйте, achmed, Вы писали:
A>Действительно .. забыл совсем . A>Интересно, использование lazy дает какое то преимущество в плане использования ресурсов перед простым оборачиванием в функцию?
В плане ресурсов вряд-ли, вот в плане удобства да.
Здравствуйте, palm mute, Вы писали:
A>>Интересно, использование lazy дает какое то преимущество в плане использования ресурсов перед простым оборачиванием в функцию?
PM>lazy гарантирует мемоизацию, но опять же, можно эмулировать функциями и ref'ами.
Напрашивается вывод что lazy это синтаксический сахар.
Здравствуйте, achmed, Вы писали:
A>Напрашивается вывод что lazy это синтаксический сахар.
Исходник из рантайма F#: мемоизация на основе mutable поля + потокобезопасность.
type Lazy<'a> =
{ /// This field holds the result of a successful computation. It's initial value is Unchecked.defaultof
mutable value : 'a
/// This field holds either the function to run or a LazyFailure object recording the exception raised
/// from running the function. It is null if the thunk has been evaluated successfully.
mutable funcOrException: obj }
static member Create(f: (unit->'a)) : Lazy<'a> =
{ value = Unchecked.defaultof<'a>;
funcOrException = box(f); }
static member CreateFromValue(x:'a) : Lazy<'a> =
{ value = x;
funcOrException = null; }
member x.IsDelayed = (match x.funcOrException with null -> false | :? LazyFailure -> false | _ -> true)
member x.IsException = (match x.funcOrException with null -> false | :? LazyFailure -> true | _ -> false)
member x.IsForced = (match x.funcOrException with null -> true | _ -> false)
member x.Force() =
match x.funcOrException with
| null -> x.value
| _ ->
// Enter the lock in case another thread is in the process of evaluting the result
System.Threading.Monitor.Enter(x);
try
x.UnsynchronizedForce()
finally
System.Threading.Monitor.Exit(x)
member x.UnsynchronizedForce() =
match x.funcOrException with
| null -> x.value
| :? LazyFailure as res ->
raise(res.Exception)
| :? (unit -> 'a) as f ->
x.funcOrException <- box(LazyFailure.Undefined)
try let res = f () in
x.funcOrException <- null;
x.value <- res;
res
with e ->
x.funcOrException <- box(new LazyFailure(e));
rethrow()
| _ ->
failwith "unreachable"
member x.SynchronizedForce() = x.Force()
member x.Value = x.Force()
and 'a ``lazy`` = Lazy<'a>
Re[4]: [F#] как устроен seq
От:
Аноним
Дата:
09.10.09 14:22
Оценка:
Здравствуйте, achmed, Вы писали:
A>Поскольку F# как и OCaml энергичный язык, для ленивого эффекта используются функции. A>Не знаю, как можно сделать ленивый список иначе.
Я собственно имел в виду, что это реализация на F#
mu A. Unit -> {'a, A}
Здравствуйте, achmed, Вы писали:
A>>Напрашивается вывод что lazy это синтаксический сахар.
A>Исходник из рантайма F#: мемоизация на основе mutable поля + потокобезопасность.
Вот интересно, если сделать мемоизированную функцию, кусающую себя за хвост?
(Прошу ногами за синтаксис не пинать — я не знаток языка... даже компилировать не пробовал. По следам собственных изысков на питоне).
fun returns v () = v
fun raises e () = raise e
type MyLazy<'a> =
{
mutable take: (unit -> 'a)
}
(* энергичная функция. просто функция. будет для нас основным конструктором *)
static member Run (f : (unit -> 'a) ) : MyLazy<'a> = { take = f; }
(* значение. просто значение *)
static member Const v = Run (returns v)
(* функция, вычисляемая единожды *)
static member RunOnce f =
let rec myl = Run (myl.Memoize f)
in myl
(* хелпер: единожды вычислить функцию и запомнить результат *)
member myl.Memoize f () =
try
let v = f () in
myl.Reset (returns v); (* после первого использования подменим на константу *)
v
with e ->
myl.Reset (raises e); (* иначе подменим на бросалку *)
rethrow ()
(* хелпер: подменяет функцию *)
member myl.Reset f = myl.take <- f
(* собственно, функция доступа *)
member myl.Force () = myl.take ()
(* вычисляем результат в последний раз *)
member myl.Freeze () = myl.Memo myl.take ()
Минусы:
— косвенный вызов каждый раз, чтобы получить значение; пусть даже это всегда, кроме первого раза, будет (returns v)()
— невозможность подсмотреть текущее состояние (полуфабрикат, результат, исключение)
А с другой стороны, нафиг надо подсматривать? Попросил — получил (или взорвался).
Кстати, логично бы хранить не два мутабельных поля (одно из которых ещё и абстрактное), а одно мутабельное вариантное
type MyExpr<'a> = MyConst of 'a | MyFunction of (unit->'a) | MyException of obj
type MyLazy<'a> =
{
mutable value : MyExpr<'a>
}
static member Const(v) : MyLazy<'a> = { value = MyConst v; }
static member RunOnce(f) : MyLazy<'a> = { value = MyFunction f; }
member myl.Take () =
match myl.value with
| MyConst v -> v
| MyFunction f ->
try
let v = f() in
myl.value = MyConst v;
v
with e ->
myl.value = MyException box(e);
rethrow()
| MyException e ->
raise e
member myl.IsForced = match myl.value with MyConst _ -> true | _ -> false
member myl.IsDelayed = match myl.value with MyFunction _ -> true | _ -> false
member myl.IsException = match myl.value with MyException _ -> true | _ -> false
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[5]: [F#] как устроен seq
От:
Аноним
Дата:
11.10.09 13:23
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, achmed, Вы писали:
A>>Поскольку F# как и OCaml энергичный язык, для ленивого эффекта используются функции. A>>Не знаю, как можно сделать ленивый список иначе.
А>Я собственно имел в виду, что это реализация на F# А>mu A. Unit -> {'a, A}
А>из TAPL (глава 20.1.2)
А может использовать такую реализацию?
open System
type Stream<'a> =
| Cons of (Unit ->'a * Stream<'a>)
let rec createStream n =
Cons(fun ()->(n, createStream(n+1)))
let x = createStream 0
let rec print (Cons(stream)) n=
if n <= 0 then ()
else
match stream() with
| (x,xs) -> printfn "%d" x
print xs (n — 1)