[F#] как устроен seq
От: Аноним  
Дата: 09.10.09 06:35
Оценка:
Возможно, баян.
http://stackoverflow.com/questions/308481/writing-the-f-recursive-folder-visitor-in-c-seq-vs-ienumerable
Обратите внимание на последнее сообщение.
Re: [F#] как устроен seq
От: achmed Удмуртия https://www.linkedin.com/in/nail-achmedzhanov-9907188/
Дата: 09.10.09 09:26
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Возможно, баян.

А>http://stackoverflow.com/questions/308481/writing-the-f-recursive-folder-visitor-in-c-seq-vs-ienumerable
А>Обратите внимание на последнее сообщение.

seq — монада, устроена так же как List из Haskell.
Что нового то?
Re[2]: [F#] как устроен seq
От: Аноним  
Дата: 09.10.09 09:59
Оценка:
Здравствуйте, achmed, Вы писали:

A>Здравствуйте, Аноним, Вы писали:


A>seq — монада, устроена так же как List из Haskell.

A>Что нового то?

Слона-то и не видно. Новое (старое?) — функциональные стримы.
type
LazyList<'a> = Cons of ('a*Stream<'a>) | Nil
and
Stream<'a> = unit -> LazyList<'a>
Re[3]: [F#] как устроен seq
От: FR  
Дата: 09.10.09 10:16
Оценка:
Здравствуйте, Аноним, Вы писали:


А>Слона-то и не видно. Новое (старое?) — функциональные стримы.

А>type
А> LazyList<'a> = Cons of ('a*Stream<'a>) | Nil
А>and
А> Stream<'a> = unit -> LazyList<'a>

Наверно старое, в OCaml аналоги есть давно.
Re[3]: [F#] как устроен seq
От: achmed Удмуртия https://www.linkedin.com/in/nail-achmedzhanov-9907188/
Дата: 09.10.09 11:57
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Слона-то и не видно. Новое (старое?) — функциональные стримы.

А>type
А> LazyList<'a> = Cons of ('a*Stream<'a>) | Nil
А>and
А> Stream<'a> = unit -> LazyList<'a>

Поскольку F# как и OCaml энергичный язык, для ленивого эффекта используются функции.
Не знаю, как можно сделать ленивый список иначе.
Re[4]: [F#] как устроен seq
От: FR  
Дата: 09.10.09 12:20
Оценка:
Здравствуйте, achmed, Вы писали:

A>Поскольку F# как и OCaml энергичный язык, для ленивого эффекта используются функции.

A>Не знаю, как можно сделать ленивый список иначе.

В OCaml есть и поддержка на уровне языка, ключевое слово lazy
Re[5]: [F#] как устроен seq
От: achmed Удмуртия https://www.linkedin.com/in/nail-achmedzhanov-9907188/
Дата: 09.10.09 12:38
Оценка:
Здравствуйте, FR, Вы писали:

FR>Здравствуйте, achmed, Вы писали:


A>>Поскольку F# как и OCaml энергичный язык, для ленивого эффекта используются функции.

A>>Не знаю, как можно сделать ленивый список иначе.

FR>В OCaml есть и поддержка на уровне языка, ключевое слово lazy


Действительно .. забыл совсем .
Интересно, использование lazy дает какое то преимущество в плане использования ресурсов перед простым оборачиванием в функцию?
Re[6]: [F#] как устроен seq
От: palm mute  
Дата: 09.10.09 12:43
Оценка: 1 (1) +1
Здравствуйте, achmed, Вы писали:

FR>>В OCaml есть и поддержка на уровне языка, ключевое слово lazy


A>Действительно .. забыл совсем .

A>Интересно, использование lazy дает какое то преимущество в плане использования ресурсов перед простым оборачиванием в функцию?

lazy гарантирует мемоизацию, но опять же, можно эмулировать функциями и ref'ами.
Re[6]: [F#] как устроен seq
От: FR  
Дата: 09.10.09 12:51
Оценка:
Здравствуйте, achmed, Вы писали:

A>Действительно .. забыл совсем .

A>Интересно, использование lazy дает какое то преимущество в плане использования ресурсов перед простым оборачиванием в функцию?

В плане ресурсов вряд-ли, вот в плане удобства да.

Ну и такое:

let x = lazy (1 / 0);;


без поддержки языка сделать затруднительно
Re[7]: [F#] как устроен seq
От: FR  
Дата: 09.10.09 12:54
Оценка:
Здравствуйте, FR, Вы писали:

FR>без поддержки языка сделать затруднительно


Тут я тормознул , завернуть в лямбду не проблема
Re[7]: [F#] как устроен seq
От: achmed Удмуртия https://www.linkedin.com/in/nail-achmedzhanov-9907188/
Дата: 09.10.09 13:02
Оценка:
Здравствуйте, palm mute, Вы писали:

A>>Интересно, использование lazy дает какое то преимущество в плане использования ресурсов перед простым оборачиванием в функцию?


PM>lazy гарантирует мемоизацию, но опять же, можно эмулировать функциями и ref'ами.


Напрашивается вывод что lazy это синтаксический сахар.
Re[8]: [F#] как устроен seq
От: achmed Удмуртия https://www.linkedin.com/in/nail-achmedzhanov-9907188/
Дата: 09.10.09 14:04
Оценка:
Здравствуйте, 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}

из TAPL (глава 20.1.2)
Re[9]: [F#] как устроен seq
От: Кодт Россия  
Дата: 09.10.09 15:37
Оценка:
Здравствуйте, 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)

print x 5

Console.ReadLine() |> ignore
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.