Как стать автором
Обновить
31
8.8
Кирилл Белов @KirillBelovTest

Инженер по автоматизации тестирования

Отправить сообщение

Ну если надо применить сложение к списку то в WL это вот так:

sum = Apply[Plus]

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

Часто причина появления open-cource кода не в том, что автор перечитал манифест Столлмана, а в том, что есть закрытый коммерческий продукт, который нужен разработчику, но ему оказывается проще сделать открытую альтернативу. Все способы монетизации, которые вы предложили просто противоречат этой цели. Если автор попытается open-source монетизировать "в лоб" (сам код, а не поддержку и не услуги), то этот код автоматически перестает быть открытым. Значит он и не нуждается в монетизации, иначе он вообще исчезнет из природы!

Вот как в WL с размерностями можно работать
https://imgur.com/a/Rt8uwWQ

Вы можете установить бесплатный fronted (который разрабатывает @jerryi и я). Там интерфейс удобнее чем командная строка. Когда у меня будет время я постараюсь сделать руководство для тех, кто впервые знакомится с языком. А пока что есть вот такая статья https://tproger.ru/articles/besplatnye-instrumenty-dlja-wolfram-language. Некоторые пункты там конечно уже не актуальны (например редактора Атом уже нет), а новых инструментов тогда еще не было

https://github.com/JerryI/wolfram-js-frontend/releases

Вы в FullSimplify два выражения через запятую написали. Поставьте вместо запятой “==“.

В общем-то я понял в чем проблема. Вы видимо установили wolfram engine, запустили ядро из командной строки и в нем в режиме REPL выполняли код. Но там можно по одной строчке выполнять только. Это же просто приложение командной строки как интерпретатор Python. Так вот вы когда два раза Cases ввели - то их результат просто умножился. Т.е. в WL умножение - это пробел как в матанализе. a b === a*b. Но! Для бесплатного ядра есть бесплатный фронтенд про который я и мой друг писал здесь же совсем недавно. @JerryI тоже может рассказать об этом

Подождите… Вы ведь умножили два списка друг на друга

Добрый день! Вы использовали Wolfram Engine?

Спасибо большое за оценку моих трудов =)
Кстати мой любимый книжный пример - это сортировка пузырьком при помощи шаблонов:

{5, 4, 2, 6, 3, 2} //. 
   {fst___, x_Integer, y_Integer, rst___} :> 
     {fst, y, x, rst} /; x > y
  • //. - сокращение для ReplaceRepeated - функция которая выполняет повторяющуюся замену

  • :> - правило замены

  • /; - дополнительное условие для замены, но не обязательное

В итоге этот код на первом шаге делает следующее. Берет весь список и сравнивает его с образцом:

MatchQ[{5, 4, 2, 6, 3, 2}, {fst___, x_Integer, y_Integer, rst___}] /; x > y

связываются fst = <ничего>; x = 5; y = 4; rst = 2, 6, 3, 2. Оказывается что 5 > 4, тогда условие выполнено и на место исходного списка вставляется:

{fst = <ничего>, y = 4, x = 5, rst = 2, 6, 3, 2} == {4, 5, 3, 6, 3, 2}

Далее этот процесс повторяется, но теперь первый и второй элемент не проходят условие и происходит новое связывание: fst = 4; x = 5; y = 2; rst = 6, 3, 2 и т.д. пока не окажется так, что заменять ничего.

Да, конечно. Это такой синтаксис шаблонов/паттернов/образцов в WL. Во многих языках программирования, в которых есть паттерн-матчинг есть такая штука как wildcard. То есть "_". Так вот в WL шаблоны могут состоять из разных вариаций wildcard. Вот несколько примеров. Сравнение происходит при помощи функции MatchQ[expression, pattern]:

MatchQ[x, _] == True (*одиночное подчеркивание - все что угодно*)
MatchQ[f[x], f[_]] == True (*это значит выражение слева это f с любым аргументом*)
MatchQ[f[x, y], f[_]] == False
MatchQ[f[], f[_]] == False

MatchQ[f[1, 2, 3, 4], f[__]] == True (*два подчеркивания от одного до бесконечности элементов*)
MatchQ[f[], f[__]] == False

MatchQ[f[], f[___]] == True
MatchQ[f[x], f[___]] == True
MatchQ[f[x, y, z], f[___]] == True (*три подчеркивания любое число элементов от 0 до беконечности*)

Кроме трех вариантов wildcard есть еще возможность указывать диапазон количества элементов или конкретное значение, но это я оставлю на потом. И так мы рассмотрели возможность матчить произвольное выражение с шаблоном, который соответствует одному "чему угодно", одному и более или нулю и более штук "чего угодно". Но что если я хочу чтобы это было не что угодно, а только выражения/объекты с определенными типами? Тогда после подчеркивания я могу напрямую указать этот тип. Как понять какой тип у выражения в языке с динамической типизацией? При помощи функции Head. Это значит что

Head[1] == Integer
Head[1.0] == Real
Head[1/3] == Rational
Head[1 + I] == Complex
Head["string"] == String
Head[x] == Symbol
Head[f[x]] == f
Head[f[x][y][z]] == f[x][y]
Head[Head[f[x][y][z]]] == f[x]

И я могу взять любой результат, который возвращает Head и вставить его сразу после одного/двух/трех символов подчеркивания. То есть вот так:

MatchQ[1, _Integer] == True
MatchQ[1.5, _Integer] == False

То есть это wildcard с проверкой типов, но не все так просто.

Вот например как можно проверить что у нас массив только целых:

MatchQ[{1, 2, 3, 4}, {__Integer}] == True

А вот так я могу проверить, что у меня есть массив где сначала идут целы числа, потом рациональные, а потом комплексные. При этом комплексных может не быть совсем

MatchQ[{1, 2, 3, 1/3, 1/5, 1/7, I, I/3}, {__Integer, __Ratonal, ___Complex}] == True
MatchQ[{1, 2, 1/5}, {__Integer, __Ratonal, ___Complex}] == True

А еще wildcard можно связать с именем вот так:

MatchQ[f[1], f[x_]] == True

В MatchQ это бесполезно, но в функции, которая вытаскивает что-то по шаблону - это полезно:

Cases[{f[1]}, f[x_] :> x] (* => {1} *)

Т.е. выше я связал значение 1 из выражения с символом x и смог извлечь это значение. Если использовать несколько подчеркиваний, то будет вот так:

Cases[{f[1, 2, 4]}, f[x__] :> {x}] (* => {{1, 2, 4}}*)

Это небольшая часть паттерн матчинга в WL но нам пока достаточно. Теперь перейдем к главному - шаблоны можно использовать в в определениях функций, т.е. создав функцию вот так:

f[x_] := x + 1

Я говорю математике о том, что как только она встречает выражение, которое матчится с:

MatchQ[f[1], f[x_]] == True

То сразу же происходит замена на правую часть определения функции - т.е. на x + 1. Определив так функция - я отсекаю все шаблоны, которые не матчатся с шаблоном f[x_]. Вызвав функцию на том, что не матчится ни с одним из шаблонов, которые были определены - ядро WL вернет результат ввода как есть. Т.е. например:

f[x_, y_] := x + y

f[1, 2, 3] (* => f[1, 2, 3] без изменений*)

Ну и возвращаясь к примеру из моего комментария выше шаблон

f[arr: {a1_Integer, ___Integer}, x_Integer] /; x < a1 := ...

Означает, что функция определена только на последовательности аргументов, которая представляет из себя:

  1. Первый аргумент список, где первый элемент списка обязательно целое число, а дальше может быть от нуля до бесконечности только целы чисел. Но я не стал писать a__Integer, чтобы связать ТОЛЬКО первый элемент списка с переменной a1, а не всю последовательность.

  2. Второй аргумент - просто целое число.

  3. После знака /; идет условие, которое может использовать связанные переменные

Если у вас возникнут вопросы после моего объяснения или я объяснил слишком запутанно - то напишите пожалуйста, я готов ответить на любые вопросы!

В общем хоть меня и удивляет популярность такой достаточно простой задачи, но я сначала дошел до условия, решил задачку, а потом продолжил читать. Не думал, что мое наивное решение и будет тем самым, которое ожидает автор статьи. Но хочу показать свое решение в коментах, так как оно оригинально тем, что сделано на WL:

f[arr : {a1_Integer, ___Integer}, x_Integer, default_Integer : -1] /; x < a1 := default

f[arr : {___Integer, an_Integer}, x_Integer, default_Integer : -1] /; x >= an := an

f[arr : {__Integer}, x_Integer, default_Integer : -1] := 
With[{halfLen = Round[Length[arr]/2]}, 
  If[arr[[halfLen]] < x, 
    f[arr[[halfLen + 1 ;; ]], x, arr[[halfLen]]], 
    f[arr[[ ;; halfLen]], x, default]
  ]
]

f::argex = "Argument exception"; 

f[args___] := (Message[f::argex]; Defer[f[args]])

На скриншоте код и результаты тестов. Результаты не уместились, но тестов больше чем в самой статье, т.е. они те же самые, а еще включают то, что не было учтено.

Я когда начинал читать - то ожидал не два уровня, а побольше. Что на первом решают в лоб за один проход. На втором - двоичным поиском, а на третьем какая-нибудь магия вроде кода Грея или еще какой-то малоизвестной штуки. Увы, ожидания не оправдались.

Я вернулся. Честно сказать не знаю, что такое DSP-процессор, хоть и нашел расшифровку. НО! Я понимаю, что скомпилированный вариант всегда будет быстрее и лучше работать для обработки сигнала в реальном времени, но в теории на WL можно сделать такое же приложение. Я не дам прямо сейчас конкретный пример, но вы можете:

  • Использовать stream = AudioStream[] чтобы получить текущий поток с устройства ввода - например с микрофона

  • Получить его свойства:

    • Текущий кусок stream["CurrentAudio"]

    • Изменить размер буфера stream["BufferSize"] = n

    • Получить текущую позицию stream["Position"]

    • Если вы читаете из файла, то позицию в потоке можно изменять

    • Аудио поток можно записывать.

    • Потому записанный обработать.

  • Объект Audio ведет себя примерно как обычный массив точек, который представляет собой сигнал. Его можно легко изменить применив любую математическую функцию. Сигналы можно делить и объединять.

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

Я вообще думаю вы слишком мягко прошлись по этим алгоритмам. На мой взгляд в принципе все программисты не важны! Зачем они вообще? Чем занимаются? Только плодят баги и доставляют нам трудности! Без них жизнь была бы проще и собеседования легче проходить. Это я вам как QA говорю, мне можно верить.

И еще. Если у вас действительно есть желание использовать в каких-то проектах WL как язык общего назначения, но что-то останавливает - это явно не должен быть синтаксис. Если у вас есть еще какие-то проблемы, с которыми вы столкнулись и в итоге отбросили WL, то я с радостью про них почитаю и подумаю есть ли решение. (Ну кроме того, что вы просто сами не хотели). Я постепенно изучал его и обнаружил, что по сути там не один порог входа, а два. Первый очень низкий. Куда ниже чем у большинства технологий. Просто запустил, посмотрел короткие туториалы и вот ты уже почти на естественном языке решаешь уравнения и берёшь интегралы.

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

Я правильно понимаю, что в C# есть оператор деления и для его переопределения вы написали класс с тремя методами. Более читабельно там только то, что в сигнатуре написано “operator /“. Плюс это конкретный класс, который может использовать только конкретные типы, а если делать обобщенный тип, то использовать его будет еще чуть-чуть сложнее. И последнее - вы не написали переопределение для “+=“, а ведь это еще один метод.

Для того же самого в WL я сделал две функциии, которые одновременно изменили поведение AddTo/Power/Times. В принципе это можно было бы и в одном определении сделать. Но я сделал так, чтобы при применении к выражению возвращалось новое выражение, а при применении к символу - изменялся сам символ. И все это с учетом того, что оператора или функции деления в WL нет.

Далее наоборот. Я предложил переопределить оператор «которого нет» в C#, вы сказали это невозможно.

Так в итоге в чью пользу складывается «зачет» по «гибкости синтаксиса»?

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

И на счет символа деления. Не знаю ни одного популярного языка программирования, который использует двоеточие в качестве оператора деления или умеет использовать горизонтальную черту. Горизонтальную черту только математические пакеты используют в лучшем случае.

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

Я все таки за то, чтобы была точность в формулировках. Когда вы говорите «хочу переопределять одно, а переопределяли другое» это неверно. Этого «одного» вообще нет в языке. В WL нет операторов и в том числе нет оператора деления. Это такой синтаксический Сахар для записи математических выражений. Если бы вы хотели переопределять то, что существует в том виде в каком записывается - это делает намного проще чем я показал и чем это сделано в c#. Например Plus или Times

Но ведь можно предложить и обратную ситуацию. Как в C# переопределять «//.» Или «/*» или “@@@“или нижний индекс?

Автоматическое в каком смысле? Как я сказал выше - для StringExpression или для RegExp нужно сначала создать правила преобразования и тогда можно будет все делать автоматически. По умолчанию аналогов Factor или Expand для StringExpression нет

Я совсем забыл, что есть DatePattern

Информация

В рейтинге
769-й
Откуда
Саратов, Саратовская обл., Россия
Зарегистрирован
Активность