- module LispFun 
- open System 
- open Autodesk.AutoCAD.ApplicationServices 
- open Autodesk.AutoCAD.DatabaseServices 
- open Autodesk.AutoCAD.EditorInput 
- open Autodesk.AutoCAD.Geometry 
- open Autodesk.AutoCAD.Runtime 
-   
- //функция преобразования переданных аргументов в список 
- //список имеет более широкие возможности сопоставления чем массив 
- //т.к. возможно сопоставить только "начальные" аргументы 
- //реализованна с помощью шаблона сопоставления 
- let Rb=function 
-   |null->[] // если ничего нет - то пустой список 
-   | (- rb:ResultBuffer )->- rb. AsArray()|>Array- . toList //если что-то передали - список аргументов
-   
- //создадим полный шаблон на некоторые типы данных 
- //возможно дополнение в этом либо другом шаблоне 
- //перегрузка Unknow - для "необработанных" типов данных 
- let (|Str|Num|T|Nil|Id|Point|Unknow|) (tv:TypedValue)= 
-   enum<LispDataType>(tv.TypeCode|>int)|>function 
-     |LispDataType.Text->Str(tv.Value:?>string) // если передан тип строка - преобразуем в строку 
-     |LispDataType.Double->Num(tv.Value:?>float) // число в любом формате приведем к float 
-     |LispDataType.Int16->Num(tv.Value:?>int16|>float) 
-     |LispDataType.Int32->Num(tv.Value:?>int32|>float) 
-     |LispDataType.T_atom->T // по аналогии остальные типы ... 
-     |LispDataType.Nil->Nil 
-     |LispDataType.ObjectId->Id(tv.Value:?>ObjectId) 
-     |LispDataType.Point3d->Point(tv.Value:?>Point3d) 
-     |_->Unknow 
-   
- let (|LstB|LstE|Ss|Unknow|) (tv:TypedValue)= // шаблон на SelectionSet и начало/конец списка 
-   enum<LispDataType>(tv.TypeCode|>int)|>function 
-     |LispDataType.ListBegin->LstB 
-     |LispDataType.ListEnd->LstE 
-     |LispDataType.SelectionSet->Ss([for id in (tv.Value:?>SelectionSet)->id.ObjectId]) 
-     |_->Unknow 
-   
- let (|AcList|_|)=function // неполный шаблон - на содержимое списка с учетом вложенных  
-   |LstB::t->let rec fn=function // если начало списка - создаем функцию разбора списка 
-               |lst, 0- ,LstE::t ->- Some (- lst |>List- . rev- ,t ) //уровень вложенности = 0 и получаем конец списка
-                                                     // - возвращаем список и данные идущие за ним 
-               |lst,x,(LstB as s)::t->fn(s::lst,x+1,t) // начало вложенного списка - повышаем уровень 
-               |lst,x,(LstE as e)::t->fn(e::lst,x-1,t) // конец вложенного списка - понижаем 
-               |lst,x,a::b->fn(a::lst,x,b) // непосредственно данные 
-               |_->failwith "Ошибка разбора" // при передачи из лисп сюда программа никак не должна попасть 
-             fn([],0,t) // запуск функцию разбора 
-   |_->None // не соответствие шаблону 
-   
- let (|Dxf|_|) code=function // неполный шаблон на сопоставление dxf кода переданного Entity 
-   |Id id when id.ObjectClass.DxfName=code->Some(id)  
-   |_->None // другой вча код или другой тип аргумента 
-   
- let (|Line|PLine|Arc|Circle|Unknow|)=function //Шаблон на некоторые примитивы 
-                                               //с отложенным получением приведенных объектов 
-   |Dxf "LINE" id->Line(lazy(id.GetObject(OpenMode.ForRead):?>Line)) 
-   |Dxf "LWPOLYLINE" id->PLine(lazy(id.GetObject(OpenMode.ForRead):?>Polyline)) 
-   |Dxf "ARC" id->Arc(lazy(id.GetObject(OpenMode.ForRead):?>Arc)) 
-   |Dxf "CIRCLE" id->Circle(lazy(id.GetObject(OpenMode.ForRead):?>Circle)) 
-   |_->Unknow 
-   
- // функции преобразования данных для возврата из lisp функции 
- let Str x=new TypedValue(int LispDataType.Text,x) 
- let Num x=new TypedValue(int LispDataType.Double,x) 
- let T=new TypedValue(int LispDataType.T_atom) 
- let Nil=new TypedValue(int LispDataType.Nil) 
-   
- [<LispFunction "XFun">]  
- let XFun arg= //сама функция 
-   Application.DocumentManager.MdiActiveDocument|>function 
-     |null->Nil //если нет активного документа 
-     |doc->let ed,db,trf=doc.Editor,doc.Database,doc.TransactionManager.StartTransaction 
-           arg|>Rb|>function //переводим ResultBuffer в список и начинаем сопоставления 
-             // первый шаблон - это два числа 
-            |[Num a;Num b]->"\nСумма двух чисел "|>ed.WriteMessage 
-                            a+b|>Num //возвращаем число из приведенных чисел 
-             // аналогично - две строки 
-            |[Str a;Str b]->"\nСцепление двух строк "|>ed.WriteMessage 
-                            a+b|>Str 
-             //Entity c DXF кодом "LINE" 
-            |Dxf  "LINE"-  line::t ->String- . Format("Получена линия с дескриптором {0}."- ,line. Handle)|>- Str 
-            |Str "Средняя точка"::AcList([Point pt1;Point pt2; Point pt3],[])-> 
-                "\nВычисляем из списка трех точек "|>ed.WriteMessage 
-                (pt1.X+pt2.Y+pt3.Z)|>Num 
-             |Num a::AcList(lst,[])->"\nЧисло и список "|>ed.WriteMessage 
-                                     a +float(- lst |>List- . length)|>- Num 
-             // если окружность и дуга или в обратном порядке (дуга, окружность) 
-             |Circle circ::Arc arc::t|Arc arc::Circle circ::t-> 
-                use tr=trf() //вызовем транзакцию внутри которой будут выполнены отложенные вычисления 
-                let ret=circ.Value.Center.DistanceTo(arc.Value.Center) 
-                tr.Commit() 
-                "\nРассстояние между окружностью и дугой "|>ed.WriteMessage 
-                ret|>Num 
-             |Str "Сколько аргументов"::t-> 
-                let rec ArgCount=function 
-                  |[]->0 
-                  |AcList(lst,b)->1+ArgCount(b) 
-                  |a::b->1+ArgCount(b) 
-                String- . Format("Количество аргументов={0}, кроме первого"- ,ArgCount t )|>- Str 
 
-             |lst  when-  lst |>List- . forall (function-  |Ss _ ->true //проверка что все аргументы - имеют тип SelectionSet
-                                                  |_->false)-> 
-                 "\nКоличество уникальных объектов в наборах "|>ed.WriteMessage 
-                 lst |>List- . collect (- function|Ss lst ->- lst 
-                                            |_->[]) 
-                    |>Seq- . distinct|>Seq- . length|>- Num 
 
-             |_->"\nНеизвестный набор параметров "|>ed.WriteMessage 
-                 Nil // если ни один шаблон не совпал