Нужно ли монетизировать каждый свой шаг? Я вот хожу в магазин и произвожу работу (надо умножить приложенную силу на расстояние), может мне за это тоже кто-то будет платить? В мире программного обеспечения есть множество всего как платного так и бесплатного. Есть разработчики, которым платят за бесплатный для пользователя продукт. Наоборот есть те, кому не платят, а продукт стоит денег (даже косвенно). Есть разработчики-волонтеры которые контрибутят в опенсорс и пользуется их трудом другой опенсорс. В общем любые комбинации платят/не платят, свободное/коммерческое, для пользователя/для другого разработчика.
Часто причина появления open-cource кода не в том, что автор перечитал манифест Столлмана, а в том, что есть закрытый коммерческий продукт, который нужен разработчику, но ему оказывается проще сделать открытую альтернативу. Все способы монетизации, которые вы предложили просто противоречат этой цели. Если автор попытается open-source монетизировать "в лоб" (сам код, а не поддержку и не услуги), то этот код автоматически перестает быть открытым. Значит он и не нуждается в монетизации, иначе он вообще исчезнет из природы!
Вы можете установить бесплатный fronted (который разрабатывает @jerryi и я). Там интерфейс удобнее чем командная строка. Когда у меня будет время я постараюсь сделать руководство для тех, кто впервые знакомится с языком. А пока что есть вот такая статья https://tproger.ru/articles/besplatnye-instrumenty-dlja-wolfram-language. Некоторые пункты там конечно уже не актуальны (например редактора Атом уже нет), а новых инструментов тогда еще не было
В общем-то я понял в чем проблема. Вы видимо установили wolfram engine, запустили ядро из командной строки и в нем в режиме REPL выполняли код. Но там можно по одной строчке выполнять только. Это же просто приложение командной строки как интерпретатор Python. Так вот вы когда два раза Cases ввели - то их результат просто умножился. Т.е. в WL умножение - это пробел как в матанализе. a b === a*b. Но! Для бесплатного ядра есть бесплатный фронтенд про который я и мой друг писал здесь же совсем недавно. @JerryI тоже может рассказать об этом
Далее этот процесс повторяется, но теперь первый и второй элемент не проходят условие и происходит новое связывание: 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 и вставить его сразу после одного/двух/трех символов подчеркивания. То есть вот так:
То есть это wildcard с проверкой типов, но не все так просто.
Вот например как можно проверить что у нас массив только целых:
MatchQ[{1, 2, 3, 4}, {__Integer}] == True
А вот так я могу проверить, что у меня есть массив где сначала идут целы числа, потом рациональные, а потом комплексные. При этом комплексных может не быть совсем
Это небольшая часть паттерн матчинга в 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 := ...
Означает, что функция определена только на последовательности аргументов, которая представляет из себя:
Первый аргумент список, где первый элемент списка обязательно целое число, а дальше может быть от нуля до бесконечности только целы чисел. Но я не стал писать a__Integer, чтобы связать ТОЛЬКО первый элемент списка с переменной a1, а не всю последовательность.
Второй аргумент - просто целое число.
После знака /; идет условие, которое может использовать связанные переменные
Если у вас возникнут вопросы после моего объяснения или я объяснил слишком запутанно - то напишите пожалуйста, я готов ответить на любые вопросы!
В общем хоть меня и удивляет популярность такой достаточно простой задачи, но я сначала дошел до условия, решил задачку, а потом продолжил читать. Не думал, что мое наивное решение и будет тем самым, которое ожидает автор статьи. Но хочу показать свое решение в коментах, так как оно оригинально тем, что сделано на WL:
На скриншоте код и результаты тестов. Результаты не уместились, но тестов больше чем в самой статье, т.е. они те же самые, а еще включают то, что не было учтено.
Я когда начинал читать - то ожидал не два уровня, а побольше. Что на первом решают в лоб за один проход. На втором - двоичным поиском, а на третьем какая-нибудь магия вроде кода Грея или еще какой-то малоизвестной штуки. Увы, ожидания не оправдались.
Я вернулся. Честно сказать не знаю, что такое 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 нет
Ну если надо применить сложение к списку то в 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?
Спасибо большое за оценку моих трудов =)
Кстати мой любимый книжный пример - это сортировка пузырьком при помощи шаблонов:
//.
- сокращение для ReplaceRepeated - функция которая выполняет повторяющуюся замену:>
- правило замены/;
- дополнительное условие для замены, но не обязательноеВ итоге этот код на первом шаге делает следующее. Берет весь список и сравнивает его с образцом:
связываются
fst = <ничего>
;x = 5
;y = 4
;rst = 2, 6, 3, 2
. Оказывается что5 > 4
, тогда условие выполнено и на место исходного списка вставляется:Далее этот процесс повторяется, но теперь первый и второй элемент не проходят условие и происходит новое связывание:
fst = 4
;x = 5
;y = 2
;rst = 6, 3, 2
и т.д. пока не окажется так, что заменять ничего.Да, конечно. Это такой синтаксис шаблонов/паттернов/образцов в WL. Во многих языках программирования, в которых есть паттерн-матчинг есть такая штука как wildcard. То есть
"_"
. Так вот в WL шаблоны могут состоять из разных вариаций wildcard. Вот несколько примеров. Сравнение происходит при помощи функцииMatchQ[expression, pattern]
:Кроме трех вариантов wildcard есть еще возможность указывать диапазон количества элементов или конкретное значение, но это я оставлю на потом. И так мы рассмотрели возможность матчить произвольное выражение с шаблоном, который соответствует одному "чему угодно", одному и более или нулю и более штук "чего угодно". Но что если я хочу чтобы это было не что угодно, а только выражения/объекты с определенными типами? Тогда после подчеркивания я могу напрямую указать этот тип. Как понять какой тип у выражения в языке с динамической типизацией? При помощи функции Head. Это значит что
И я могу взять любой результат, который возвращает Head и вставить его сразу после одного/двух/трех символов подчеркивания. То есть вот так:
То есть это wildcard с проверкой типов, но не все так просто.
Вот например как можно проверить что у нас массив только целых:
А вот так я могу проверить, что у меня есть массив где сначала идут целы числа, потом рациональные, а потом комплексные. При этом комплексных может не быть совсем
А еще wildcard можно связать с именем вот так:
В MatchQ это бесполезно, но в функции, которая вытаскивает что-то по шаблону - это полезно:
Т.е. выше я связал значение 1 из выражения с символом x и смог извлечь это значение. Если использовать несколько подчеркиваний, то будет вот так:
Это небольшая часть паттерн матчинга в WL но нам пока достаточно. Теперь перейдем к главному - шаблоны можно использовать в в определениях функций, т.е. создав функцию вот так:
Я говорю математике о том, что как только она встречает выражение, которое матчится с:
То сразу же происходит замена на правую часть определения функции - т.е. на x + 1. Определив так функция - я отсекаю все шаблоны, которые не матчатся с шаблоном f[x_]. Вызвав функцию на том, что не матчится ни с одним из шаблонов, которые были определены - ядро WL вернет результат ввода как есть. Т.е. например:
Ну и возвращаясь к примеру из моего комментария выше шаблон
Означает, что функция определена только на последовательности аргументов, которая представляет из себя:
Первый аргумент список, где первый элемент списка обязательно целое число, а дальше может быть от нуля до бесконечности только целы чисел. Но я не стал писать a__Integer, чтобы связать ТОЛЬКО первый элемент списка с переменной a1, а не всю последовательность.
Второй аргумент - просто целое число.
После знака
/;
идет условие, которое может использовать связанные переменныеЕсли у вас возникнут вопросы после моего объяснения или я объяснил слишком запутанно - то напишите пожалуйста, я готов ответить на любые вопросы!
В общем хоть меня и удивляет популярность такой достаточно простой задачи, но я сначала дошел до условия, решил задачку, а потом продолжил читать. Не думал, что мое наивное решение и будет тем самым, которое ожидает автор статьи. Но хочу показать свое решение в коментах, так как оно оригинально тем, что сделано на WL:
На скриншоте код и результаты тестов. Результаты не уместились, но тестов больше чем в самой статье, т.е. они те же самые, а еще включают то, что не было учтено.
Я когда начинал читать - то ожидал не два уровня, а побольше. Что на первом решают в лоб за один проход. На втором - двоичным поиском, а на третьем какая-нибудь магия вроде кода Грея или еще какой-то малоизвестной штуки. Увы, ожидания не оправдались.
Я вернулся. Честно сказать не знаю, что такое 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
Встроенной функции нет, но вот такая штука есть:
https://resources.wolframcloud.com/FunctionRepository/resources/ToRegularExpression/