четверг, 11 ноября 2010 г.
воскресенье, 7 ноября 2010 г.
среда, 27 октября 2010 г.
Upd. Паттерн матчинг
В догонку к предыдущему сообщению.
let find = function | "by" :: "name" :: _ :: [] -> 3 | "by" :: "autor" :: _ :: [] -> 4 | "by" :: "autors" :: _ :: [] -> 5 | _ -> 0
и
let find = function | "by" :: "name" :: t when t <> [] -> 3 | "by" :: "autor" :: t when t <> [] -> 4 | "by" :: "autors" :: t when t <> [] -> 5 | _ -> 0Так вот, 2й вариант значительно хуже! Он развернётся аж в две функции, каждая из которых будет сложнее того, во что развернётся 1й варинт(листинги приводить не буду - всё это можно увидеть в рефлекторе).
Паттерн матчинг и выделение памяти
Есть небольшой и довольно простой код:
let replace = function | "by" :: "id" :: t :: [] -> 8 | _ -> 0
t :: [] - используется для того, чтобы гарантировать наличие одного свободного эл-та в списке.
И вроде бы всё хорошо, но если посмотреть в рефлекторе, то можно увидеть такую картину:
public static int replace(FSharpList<string> _arg1)
{
if (_arg1.get_TailOrNull() != null)
{
FSharpList<string> list = _arg1;
if (string.Equals(list.get_HeadOrDefault(), "by")
&& (list.get_TailOrNull().get_TailOrNull() != null))
{
FSharpList<string> list2 = list.get_TailOrNull();
if (string.Equals(list2.get_HeadOrDefault(), "id")
&& (list2.get_TailOrNull().get_TailOrNull() != null))
{
FSharpList<string> list3 = list2.get_TailOrNull();
if (list3.get_TailOrNull().get_TailOrNull() == null)
{
string t = list3.get_HeadOrDefault();
return 8;
}
}
}
}
return 0;
}
Выделенная строка намекает на то, что выделяется память под ту же ссылку(а это лишняя работа).
Но, если использовать _ вместо t, то всё становится несколько радужней:
public static int replace(FSharpList<string> _arg1)
{
if (_arg1.get_TailOrNull() != null)
{
FSharpList<string> list = _arg1;
if (string.Equals(list.get_HeadOrDefault(), "by")
&& (list.get_TailOrNull().get_TailOrNull() != null))
{
FSharpList<string> list2 = list.get_TailOrNull();
if ((string.Equals(list2.get_HeadOrDefault(), "id")
&& (list2.get_TailOrNull().get_TailOrNull() != null))
&& (list2.get_TailOrNull().get_TailOrNull().get_TailOrNull() == null))
{
return 8;
}
}
}
return 0;
}
Как можно заметить код становится значительно проще(пропадает один вложенный иф + не выделяется память под t + не вычисляется list3).
Отсюда нехитрый вывод - следует, по возможности, использовать запись вида h :: _ :: t вместо h :: elem :: t.
вторник, 26 октября 2010 г.
mutable привязки, интерпретатор и массивы
Есть такой код:
let mutable x =
загоняем его в интерпретатор и получаем соотв.:
val mutable x : int [] = [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|]
val to_null : unit = ()
Всё правильно, всё логично.
А теперь снова засунем в интерпретатор x:
val mutable x : int [] = [|1; 2; 3; 4; 5; 2; 3; 5; 6; 3|]
и вызовет to_null:
> to_null;;
val it : unit = ()
> x;;
val it : int [] = [|1; 2; 3; 4; 5; 2; 3; 5; 6; 3|]
Поэтому следует быть осторожным при работе с mutable привязками в интерпретаторе и, по крайней мере, перезагружать их при каждой загрузке кода в fsi.
let mutable x =
[| 1; 2; 3; 4; 5; 2; 3; 5; 6; 3; |] let to_null = for i in 0..9 dox.[i] <- 0
загоняем его в интерпретатор и получаем соотв.:
val mutable x : int [] = [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|]
val to_null : unit = ()
Всё правильно, всё логично.
А теперь снова засунем в интерпретатор x:
val mutable x : int [] = [|1; 2; 3; 4; 5; 2; 3; 5; 6; 3|]
и вызовет to_null:
> to_null;;
val it : unit = ()
> x;;
val it : int [] = [|1; 2; 3; 4; 5; 2; 3; 5; 6; 3|]
Поэтому следует быть осторожным при работе с mutable привязками в интерпретаторе и, по крайней мере, перезагружать их при каждой загрузке кода в fsi.
Подписаться на:
Сообщения (Atom)