2016-12-06 2 views
10

Я просто столкнулся с изменением в поведении между каркасными версиями при компиляции этот кусок кода в F #:Почему поведение Lazy.CreateFromValue изменилось в F # между версиями платформы .NET?

let test = Lazy.CreateFromValue 1 

Составитель против .NET Framework 2.0, результаты экспрессии в качестве «уже созданного» Ленивый объекта, то есть:

test.IsValueCreated = true 

При компиляции с .NET Framework 4.0, результаты выражения в "невычисленном" ленивом объекте, то есть:

test.IsValueCreated = false 

Только после доступа к test.Value в последнем случае эти два эквивалента.

Я никак не мог найти ссылку на это изменение, поэтому мой вопрос в том, почему это ведет себя по-разному и какова была причина изменения (это нарушение). По-моему, поведение в .NET 2.0 имеет больше смысла - создание Lazy-объекта из конкретного значения должно привести к «уже оцененному» ленивому объекту.

+4

Если это уже оценено, вряд ли можно сказать, что его оценили лениво ... –

+3

@MarkSeemann Да, но в .NET 2 это не лениво оценивается, поэтому я вижу, почему возникает какая-то путаница. Более того, fsharp.core делает странный материал в .NET 2, чтобы он выглядел как ленивый, но он не ленив. –

ответ

13

Перед .NET 4.0 фреймворк не отправлен с номером Lazy<'T>.

Это древняя история, но у F # первоначально была своя реализация Lazy, отличная от того, что у нас есть сегодня - вы можете поймать проблеск ее here.

Эта реализация была отменена, когда стало ясно, что Lazy подходит к самой структуре. Вместо этого F # 2.0 поставляется со своей собственной реализацией System.Lazy<'T> (обратите внимание на пространство имен) в сборке FSharp.Core. Это реализация, которую вы все еще можете увидеть here. Идея заключалась в том, что, как только .NET 4.0 будет доступен, F # будет легко поднимать System.Lazy<'T> оттуда, не нарушая пользователей. Это работало по большей части, но это было не совсем без проблем.

Вы заметите, что реализация F # имеет член CreateFromValue, который дает значение типа Lazy<'T>, уже отмеченное как оцененное. Это имеет смысл семантически, так как вы, очевидно, даете ему оцененное значение в первую очередь.

Почему тогда реализация .NET 4.0 не делает то же самое?

Если вы посмотрите на documentation на номер Lazy<'T>, вы обнаружите, что его невозможно создать в оцениваемом состоянии.На нем нет элемента CreateFromValue, и никакой конструктор не принимает значение 'T, только Func<'T>. CreateFromValue фактически предоставлен как extension method от F #.

Было бы довольно легко обеспечить этот метод в неразрывном пути:

static member CreateFromValue(value : 'T) : System.Lazy<'T> = 
    let x = System.Lazy<'T>.Create(fun() -> value) 
    x.Value |> ignore 
    x 

, но этого не произошло по каким-то причинам. Возможно, это был преднамеренный выбор - я полагаю, вы могли бы спорить и против таких изменений, и, возможно, это был надзор. Если вы посмотрите на свернутую историю этого типа, я думаю, вы согласитесь, что это могло быть хуже.

4

Класс Lazy<T> был добавлен в фреймворк .NET 4. Поддержка F # для lazy - это скорее заглушка, позволяющая API работать на .NET 2, но не дает поистине ленивой реализации при использовании этого API.

Компилятор F # создал own lazy type для .NET 2, поскольку он предшествовал версии .NET 4. В .NET 2 ленивый тип просто устанавливает значение явно и не является действительно ленивым (см. source) при использовании CreateFromValue.

Из-за этого, CreateFromValueextension on .NET 4 действительно ленив - он создает ленивый тип с функцией, которая возвращает значение. На .NET 2, internal type is used instead, который выполняет API Lazy<'T>.CreateFromValue, но на самом деле не ленив.

+1

Это просто неправда. У F # был «полностью функциональный» «Lazy» в .NET 2, но поскольку в то время в структуре не было «Lazy», [у него была собственная реализация] (https://github.com/fsharp/fsharp /blob/84b6da1bfcdc748ba1a79444f70e04708c6d3324/src/fsharp/FSharp.Core/prim-types.fs#L6296). – scrwtp

+1

'CreateFromValue' реализован по-разному, но, как заметил @MarkSeemann, вряд ли можно сказать, что он лениво оценивается, если он уже оценен. Во всяком случае, версия F # на самом деле имеет больше смысла. – scrwtp

+0

@scrwtp Не было ленивого, если вы используете createfromvalue в .NET 2 - я передумаю, потому что я написал это плохо. –

Смежные вопросы