Лямбда-выражения и имена функций
Лямбда-выражение не является именем функции . имена функций в Common Lisp определены как символов или (setf symbol) . лямбда-выражение в основном является встроенным синтаксисом для описания анонимной функции.
Обратите внимание, что лямбда-выражения сами по себе не имеют смысла в Common Lisp. Они появляются только в лямбда-форме (см. Ниже) и внутри формы со специальным оператором function
.
Списки в виде форм
Является ли LAMBDA особым исключением из жестко установленного правила, согласно которому первый элемент вычисляемого выражения должен быть именем некоторого операция, или есть какой-то более непротиворечивый набор правил, который я неправильно понимаю?
blockquote>Спецификация Common Lisp определяет, что существует только четыре формы на основе списка . Форма является допустимым куском кода на Лиспе.
- специальные формы (форма начинается со специального оператора)
- макроформы (форма начинается с макрооператора)
- функциональные формы (форма начинается с оператора функции )
- лямбда-формы (форма начинается с лямбда-выражения)
См. Common Lisp HyperSpec: Conses as Forms .
Обратите внимание, что в Common Lisp нет механизма, расширяющего это. Есть только эти четыре типа форм на основе списка. Можно подумать о расширениях: массивы как функции, объекты CLOS как функции, различные типы функций, такие как fexprs, переменные ... Ни один из них не поддерживается синтаксисом Common Lisp для форм на основе списков, и нет переносимого механизма для их добавления. .
LAMBDA
LAMBDA
преследует в Common Lisp две разные цели:
- это глава лямбда-выражения .
- в качестве макроса
LAMBDA
. Это расширяет(lambda ....)
в(function (lambda ....))
Макрос
LAMBDA
был добавлен в Common Lisp после определения первого языка CLtL1 для удобства, чтобы можно было писать(lambda (x) x)
вместо(function (lambda (x) x))
или#'(lambda (x) x)
. Таким образом, это аббревиатура для формы специального оператора функции и делает код более простым и похожим на Схематически .
Я тоже борюсь с двунаправленной синхронизацией двух коллекций для использования с WPF через MVVM. Я написал MVVM: оборачивать или не оборачивать? Насколько ViewModel должна оборачивать модель? (Часть 1) и MVVM: переносить или не переносить? Должны ли ViewModels также обертывать коллекции? (Часть 2) по вопросу, включая пример кода, который показывает двустороннюю синхронизацию. Однако, как отмечается в сообщениях, реализация не идеальна. Я бы квалифицировал это как доказательство концепции.
Мне нравятся фреймворки BLINQ , CLINQ и Obtics , о которых писал Alex_P. Это очень хороший способ получить одну сторону поведения при синхронизации. Может быть, другая сторона (от ВМ к Модели) может быть реализована альтернативным путем? Я только что разместил в своем блоге часть 3 , в которой обсуждаются некоторые из этих вопросов.
Насколько я могу судить, двунаправленная передача через BLINQ и CLINQ не поддерживается в тех случаях, когда оператор LINQ проецирует данные в новую структуру.
Однако похоже, что CLINQ может поддерживать двунаправленную синхронизацию в случаях, когда запрос LINQ возвращает тот же тип данных, что и базовая коллекция. Это скорее сценарий фильтрации, который не соответствует варианту использования ViewModel, заключающего данные в модель.
С моим библиотека ObservableComputations можно создать ObservableCollection, который является результатом вычислений по другому ObservableCollection и является synchoronized с нею. Вы делаете стандартные операции (добавьте, удалите) на исходном наборе: вычисленный Набор отражает все изменения:
Filtering<Order> expensiveOrders = orders.Filtering(o => o.Price > 25);
expensiveOrders.CollectionChanged += (sender, eventArgs) =>
{
// see the changes (add, remove, replace, move, reset) here
};
// Start the changing...
orders.Add(new Order(8, 30));
orders.RemoveAt(1);
orders[0].Price = 60;
orders[4].Price = 10;
orders.Move(5, 1);
orders[1] = new Order(10, 17);
Лично я использую Наблюдаемую Коллекцию в своей модели и своей видовой модели.
class Model
{
public ObservableCollection<Foo> Foos;
}
class ViewModel
{
public Model Model;
public ObservableCollection<FooView> Foos;
public ViewModel()
{
Model.Foos.CollectionChanged += OnModelFoosCollection_CollectionChanged;
}
void OnModelFoosCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Foo re;
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
re = e.NewItems[0] as Foo;
if (re != null)
AddFoo(re); //For other logic that may need to be applied
break;
case NotifyCollectionChangedAction.Remove:
re = e.OldItems[0] as Foo;
if (re != null)
RemoveFoo(re);
break;
case NotifyCollectionChangedAction.Reset:
Foos.Clear();
/* I have an AddRange in an ObservableCollection-derived class
You could do Model.Foo.ForEach(ree => AddFoo(ree));
*/
var converter =
from ree in Model.Foo
select new FooView(ree);
Reports.AddRange(converter);
break;
default:
//exercise for the reader :)
s_ILog.Error("OnModelFoosCollection_CollectionChangedDid not deal with " + e.Action.ToString());
break;
}
}
void AddFoo(Foo f)
{
Foos.Add(new FooView(f));
}
void RemoveFoo(Foo f)
{
var match = from f in Foos
where f.Model == f //if you have a unique id, that might be a faster comparison
select f;
if(match.Any())
Foos.Remove(match.First());
}
}
Теперь, когда вы удаляете что-то из коллекции Foo модели, она автоматически удалит соответствующий FooView. Это соответствует тому, как я думаю о таких вещах. Если я хочу что-то удалить, то Модель - это то место, где действительно нужно что-то удалить.
Похоже на много кода, но на самом деле не так уж и много. Я уверен, что можно было бы построить общую версию, но IMO вы всегда заканчиваете тем, что вам нужна индивидуальная логика, связанная с добавлением/удалением элементов.
Единственная ситуация, когда вам может потребоваться двусторонняя синхронизация, - это когда элемент управления, который вы используете для визуализации своей коллекции виртуальных машин, не сообщает вам о намерении пользователя создать или удалить элемент. Т.е. элемент управления имеет дело непосредственно с вашей коллекцией виртуальных машин, и ЕДИНСТВЕННЫЙ способ узнать, что элемент был добавлен / удален, - это мониторинг коллекции виртуальных машин. Если это не так, вы можете реализовать одностороннюю синхронизацию и добавлять / удалять элементы непосредственно в коллекции модели.
РЕДАКТИРОВАТЬ: Возьмем, к примеру, элемент управления WPF DataGrid , привязанный к наблюдаемой коллекции ItemViewModels. Если для его свойства CanUserAddRows установлено значение true и пользователь начинает вводить текст в пустой строке внизу, DataGrid будет использовать конструктор по умолчанию вашего { {1}} ItemViewModel, чтобы создать свободный элемент , а затем добавит его в коллекцию .Нет никаких указаний от DG, что он хочет добавить элемент в коллекцию.c Я не могу придумать другого сложного элемента управления { {1}} достаточно, чтобы иметь возможность добавлять элементы в коллекцию самостоятельно.
Противоположный сценарий - это когда у вас есть ListView , привязанный к вашей коллекции, и команда , которая указывает на намерение пользователя добавить новый item - затем в обработчике команд вы просто добавляете новый элемент в DataModel и позволяете односторонней синхронизации делать остальную работу. В этом случае ListView не может добавлять в коллекцию, которую представляет.
Что касается самого процесса синхронизации, посмотрите проект Bindable LINQ - он может минимизировать объем кода и улучшить читаемость. Например, код, опубликованный Томом, будет выглядеть примерно так:
class ViewModel
{
public Model Model;
public ObservableCollection<FooView> Foos;
public ViewModel()
{
Foos = from foo in Model.Foos.AsBindable()
select new FooView(foo);
}
}
РЕДАКТИРОВАТЬ 2: После использования B-LINQ в течение некоторого времени я должен сказать, что у вас могут возникнуть проблемы с производительностью. Я использовал его для синхронизации коллекций относительно больших коллекций (сотни элементов) с десятками элементов, добавляемых и удаляемых каждую секунду, и мне пришлось отказаться от него и реализовать синхронизацию так, как предлагал Том.
Я все еще использую B-LINQ, хотя в тех частях проекта, где коллекции небольшие и производительность не является проблемой.
Я написал несколько вспомогательных классов для обертывания наблюдаемых коллекций бизнес-объектов в их аналогах модели представления здесь , возможно, его следует расширить, чтобы пойти другим путем. всегда ищу помощь ...
Я предложил общий фреймворк Undo / Redo, основанный на MVVM, который использует некоторые техники, связанные с описанной вами проблемой. Он использует коллекции, реализующие этот интерфейс:
public interface MirrorCollectionConversor<V, D>
{
V GetViewItem(D modelItem, int index);
D GetModelItem(V viewItem, int index);
}
(V - для элементов ViewModel, D - для элементов модели)
Используя этот интерфейс, он автоматически синхронизирует коллекцию viewmodel при изменении коллекции модели. Если вы изменяете модель представления, изменения просто перенаправляются в коллекцию модели.
Функция GetViewItem дает вам некоторую гибкость в том, как объекты viewmodel связаны с его аналогами модели.
Подробности вы можете найти здесь
(признаю, что конструкция довольно сложная, и я буду очень рад выслушать предложения).