Pull to refresh
9
0
Send message

Цели самое вероятное, в полном захвате аудитории

Типа того, но есть нюансы. Скорее, не в захвате аудитории, а в цензуре.

Чтобы захватить аудиторию, нужно что-то делать. Производить "нужный" контент и/или поддерживать/стимулировать тех, кто его производит. Больше похоже на то, что просто хотят запретить тех, кто производит "ненужный" контент.

Когда говорят про гугл не выполняет требований, почему-то забывают, что многие тысячи обращений были выполнены гуглом, несмотря на отсутствие офисов в РФ.

Нет, не забывают. Гугл выполняет требования, но не все.

Если водитель проехал на красный, то его штрафуют без учёта того, сколько раз он на красный остановился.

А потом стали банить из-за санкций.

Гугл банит из-за санкций, чтобы не нарушить законы США. При этом он нарушает законы РФ. Это не гугл плохой, а жизнь такая.

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

Да. Зато мухи отделены от котлет. Я описал, какие это даёт преимущества.

я всегда был противником давать некоторым константам имя

Есть константы, назначение которых очевидно. 60 относится к таким в данном примере. Если назначение константы не очевидно, то имя делает код более читабельным.

А можно это делать только по мере накопления реальных задач.

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

нужно от всех людей отобрать мужчин? - дерево

Для этих целей больше подходит СУБД. Разные запросы клиента будут обрабатывать разные функции (обработчики). В каждой конкретной функции обычно либо нужен массив/список, либо дерево/словарь, но не то и другое вместе.

А поддерживать (обновлять) массив и индекс в коде - вообще что-то странное. Особенно, когда доступ к сайту через балансировщик.

это "долго" совершенно некритично

Ещё как критично. Если юнит-тесты работают 20 минут, то их будут редко запускать. А желательно их запускать перед каждым коммитом (в идеале - автоматически).

да но я выше говорил, что разбиение на такие функции приводит к увеличению числа строк - снижению лакончичности

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

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

бизнес-цель - ин-мемори кеш для микросервиса, например

А массив зачем?

я ничего не понял. Можно пример?

Пусть есть простая задача: прочитать файл и вывести все строки, которые содержат "goto".

Типичное решение:

void Main()
{
	var path = Console.ReadLine();
	var lines = File.ReadAllLines(path);
	
	foreach (var line in lines)
		if (line.Contains("goto"))
			Console.WriteLine(line);
}

Подобный код я постоянно встречаю на форумах. Видимо, так студентов в институтах учат. Но у этого кода много проблем.

Правильный код:

void Main()
{
	var path = Console.ReadLine();
	var lines = File.ReadAllLines(path);
	
	var result = Proceed(lines, "goto");
	
	foreach (var s in result)
		Console.WriteLine(result);
}

IEnumerable<string> Proceed(string[] lines, string needle)
{
	foreach (var line in lines)
		if (line.Contains(needle))
			yield return line;
}

Обработка отделена от вывода и не содержит магических констант ("goto").. Можно менять источник данных и/или формат вывода, не трогая бизнес-логику. Можно юнит-тесты написать.

тестирование бизнеслогики без БД смысла имеет мало

Если бизнес-логики нет (только круд), то да.

гораздо дешевле тестирование делается так

Это долго для unit тестов.

Вряд ли аналог на хацкеле уложится в такое же количество символов :)

Я не совсем понял, что этот код делает (где тут разбиение на строки). Функции map, splitOneOf и filter в Haskell есть.

parseCsv = map (filter (not . isSpace) . splitOneOf ";,") . lines 

Символов больше.

При наличии исключений

В Haskel есть и ошибки, и исключения.

как ни дели. если микросервис ходит в БД, то идемпотентными будут разве что функции конверсии объектов

Чистая функция с бизнес-логикой принимает объекты, полученные из БД, и возвращает объекты, которые нужно сохранить в БД.

Он не может повлиять на ютуб в США, только в России.

Да. Рутуб никогда не догонит ютуб, просто потому, что он охватывает очень маленький кусочек рынка.

его нерыночные механизмы

Это делается не ради прибыли. Предположу, что для менеджеров Газпрома Рутуб - это головная боль. Им сказали, что надо импортозаместить, вот они и мучаются. А прибыль, даже если она будет, это для Газпрома копейки.

и как это планируется делать на языке, где мутабельных переменных нет?

Примерно так же, как из консоли читать или в консоль писать. Суть та же самая.

Упрощённо. Чистая функция принимает объекты (которые прочитаны из БД) и возвращает объекты (которые нужно в БД сохранить). И будет грязная функция без сложной логики, которая прочитала из БД, вызвала чистую функцию, сохранила в БД.

функцию, возвращаемое значение которой зависит от значений в БД и (или) текущего времени, требуется так же тестировать как и все прочие.

Такую функцию можно разбить на две. Одна делает только получение значений из БД или текущего времени. Её не надо тестировать. А в другой вся бизнес-логика. Это чистая функция.

Например, делаем текущее время входным параметром функции. Функция становится чистой. А системную функцию, возвращающую текущее время, нет смысла тестировать.

ошибки могут выявиться и в ней

Вероятность ошибок в подобных библиотеках близка к нулю.

Вот "чем диктуется" - мне довольно вторично. А вот что диктуется - довольно много эмоций вызывает.

Диктуется в первую очередь синтаксисом языка

def f1 (lst):
	[2*x for x in lst if x > 3]

def f2 (lst):
	list(map(lambda x: 2*x, filter(lambda x: x > 3, lst)))

Вроде, в Python есть и map, и filter.... Только кто их будет использовать, если получается длиннее, и с первого раза сложно написать без ошибок.

f1 = map (*2) . filter (>3)

Вот в Haskell удобно использовать map и filter

На втором месте - привычки конкретного программиста.

И теперь в каждой первой функции люди вынуждены через строку выписывать

Чтобы убрать все эти ифы, придумали монаду Either.

Java везде использует ООП и потому является ООП языком

Современный Java использует элементы ФП на каждом шагу. Например, параметрический полиморфизм.

Использование ключевого слова class не является признаком ООП кода. Оно может использоваться для объявления модуля (с функциями, не требующими экземпляра... как в случае Helloworld), либо классической сишной структуры. Признаком ООП является наследование кода (то есть, наследование от класса, а не от интерфейса).

уже порядка 6500 ключевых слов

Не использую ни то, ни другое. Но, подозреваю, что всё не так просто. Наверное, 6500 не ключевых слов, а комбинаций ключевых слов и параметров. А для использования SysVInit недостаточно знать баш. Нужно знать, что вызывать и с какими параметрами.

Вот например нечто вроде

SQL предназначен для манипуляций с данными. Для реализации бизнес-логики он не подходит. Классический SQL даже не тьюринг-полный.

доля чистых функций (моё имхо) при реальном программировании: микросервисы, десктопные программы, сервера, БД, итп - не более 1% в коде.

Это зависит от того, как делить код на функции.

Вопрос, а где здесь находится собственно этот самый АДТ?

Первые три строки. Данный тип является суммой произведений: void + Int + Tree*Tree.

на Rust (универсальный язык), уже есть оператор enum позволяющий в то же самое

Да. В Rust есть АТД (ключевое слово enum).

Что Вы бы делали в ФЯ, когда пользователь вызывает update, create или delete?

В Haskell в этом случае используется монада IO (ввод/вывод).

итак фунциональным язык называется, если он не использует мутабельные переменные.

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

Небольшое отступление. Императивному программированию противопоставляется декларативное программирование. ФП - наиболее популярная парадигма из декларативных. ООП - это наиболее популярная парадигма из императивных. Поэтому дальше я буду сравнивать ООП и ФП.

Вы путаете парадигмы программирования и языки, которые их используют. При этом подход к ООП языкам и ФП языкам у Вас диаметрально противоположный. Согласно Вашей теории, если ООП язык использует что-то не из ООП, то он продолжает оставаться ООП языком. А если ФП язык использует что-то не из ФП, то он перестаёт быть ФП языком. И, как неизбежное следствие (из ложных предпосылок), ООП языки не чураются нового, а ФП языки используют только ФП.

Язык, позволяющий использовать как функциональные так и процедурные подходы назовём "Универсальным". А его сущность будем определять по тому в каком стиле написано большинство его библиотек (приложений на нём).

При определении стиля Вы собираетесь использовать ту же логическую ошибку, описанную выше? То есть, если в коде встретилось что-то не из ФП, то это не ФП стиль, но если в коде встретилось что-то не из ООП, то это всё ещё ООП стиль?

Практически любое приложение, написанное на императивных языках, местами использует декларативный стиль: SQL для запросов к БД, файлы конфигурации и так далее. Но от этого язык не перестаёт быть императивным.

Кроме того, используемый стиль зависит о привычек конкретного программиста. Большинство программистов привыкли писать в ООП стиле. Когда я начал изучать F#, то для практики решал задачи с сайта эйлер. Решив около сотни задач, я внезапно осознал, что пишу так же, как привык писать на C#, только вместо циклов использую рекурсию. И только когда я начал изучать Haskell, я начал понимать, что такое функциональный стиль.

Но язык ведь совершенно один и тот же. Таким образом производительность зависит от выбранной технологии реализации

Именно поэтому, сравнивая языки, не имет смысла говорить о производительности. Тем более, не имеет смысла говорить о теоретически возможной производительности, так как на практике она в большинстве случаев не достигается. Так, например, исследования кода, выложенного в интернет, показали, что программы на Haskell в среднем производительней программ на C++, решающих ту же задачу.

Ну и если сравнивать, то вводить второй критерий - читабельность/лаконичность.

Это не второй, а основной критерий.

Во-первых, популярность языков никак не связана с производительностью имеющихся реализаций.

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

Можете преобразовать свою программу на поиск первого вхождения символа A вместо 0?

Моя программа искала длину, а не вхождение 0. Приведённый Вами код возвращает первое вхождение символа А, если гарантируется, что он там есть. Аналогичный код

f xs = head [ i | (x,i) <- zip xs [0..], x=='A']

В Haskell строка - это связанный список. Поиск индекса элемента в связанном списке - довольно странная задача. Скорее всего, Вы ищете индекс как промежуточный результат для решения другой (основной) задачи. В Haskell эта задача будет решаться без поиска индекса.

да пробовал.

Какие конкретно монады использовались в отлаживаемом коде?

В этом месте, кстати, мутабельность снова рулит и бибикает, поскольку внутри тестов позволяет сделать, например, инжекшены, чтобы упростить моделирование ситуации.

Инжекшены нужны только для отладки ООП кода. Например, чтобы создать объект "хттп запрос", нужен объект "хттп контекст" и т.д., и т.п.

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

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

Микросервис для доступа к БД использует некую библиотеку. Когда я тестирую микросервис, мне не нужно тестировать эту библиотеку.

давайте сейчас попрошу

Есть типы-суммы (enum в Си) и типы-произведения (struct в Си). Но в реальной жизни чаще встречаются типы "суммы произведений". Например, двоичное дерево - это пустое дерево или лист (со значением) или узел (с двумя поддеревьями).

data Tree = Nil
          | Leaf Int
          | Node Tree Tree

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

size Nil = 0
size (Leaf _) = 1
size (Node left right) = size left + size right

Как мы видим, код функции практически дословно повторяет её (алгоритма) описание на английском языке.

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

public enum TreeTag
{
	Leaf,
	Node,
}


public abstract class Tree
{
	public TreeTag Tag { get; set; }
	
	protected Tree(TreeTag tag)
	{
		Tag = tag;
	}
}

public class Leaf : Tree
{
	public int Value { get; set; } 
	
	public Leaf(int value) : base(TreeTag.Leaf)
	{
		Value = value;
	}
}

public class Node : Tree
{
	public Tree Left { get; set; }
	public Tree Right { get; set; }
	
	public Node (Tree left, Tree right) : base(TreeTag.Node)
	{
		Left = left;
		Right = right;
	}
}

Функция, определяющая размер дерева:

int Size(Tree tree)
{
	if (tree == null)
	{
		return 0;
	}
	
	switch (tree.Tag)
	{
		case TreeTag.Leaf:
			return 1;
		case TreeTag.Node:
			var node = (Node)tree;
			return Size(node.Left) + Size(node.Right);
		default:
			throw new NotImplementedException();
	}
}

Либо, если нет желания осуществлять приведение указателя к правильному типу, прежде чем выполнить нужную операцию, можно использовать паттерн Посетитель (visitor).

В последних версиях C#, используя сопоставление с образцом, можно записать код существенно короче и более выразительно:

public abstract class Tree
{
}

public class Leaf : Tree
{
	public int Value { get; set; } 
}

public class Node : Tree
{
	public Tree? Left { get; set; }
	public Tree? Right { get; set; }
}

int Size(Tree tree) => 
	tree == null ? 0 : tree switch
	{
		Leaf leaf => 1,
		Node node => Size(node.Left) + Size(node.Right),
		_ => throw new NotImplementedException()

	};

Но всё равно вместо трёх строк приходится описывать три класса.

p.s. Обратите внимание, что в последнем варианте кода используется монада Nullable. В C# для неё есть специальный синтаксис, и она используется очень активно. Для других монад можно использовать linq-синтаксис. В системной библиотеке описана монада IEnumerable. Её используют иногда. В основном для сложных запросов (с join и т.п.), предпочитая в простых случаях использовать обычные цепочки вызовов. Свои монады практически никто не описывает. А всё из-за того, что для них нет удобного синтаксиса. То есть, мало дать возможность описать монаду, нужно также предоставить удобный синтаксис для монад.

я не вижу необходимости в таком сравнении.

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

если хацкель сравнивать по скорости то с компиляторным же языком

Когда Вы сравниваете два языка по производительности, а в сравнении другой пары языков отказываетесь учитывать производительность, то это называется подтасовкой.

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

В парсинге такая штука часто встречается, да много ещё где

Я написал несколько парсеров и ни разу не встречал такой необходимости. Более того, сама мысль о том, что мне совсем не важно, какие там следующие (ровно) 3 символа, необычна.

она считает длину всего, что длина заранее посчитана

Нет. Изучите матчасть.

но она не сравнивает с нулём

Длину можно вычислить без сравнения с нулём. Длину можно вычислить вообще без сравнений.

большинство библиотек (это моё предположение) написаны в функциональном стиле. Я прав?

Нет. Больше библиотек написано на C#.

F# является функциональным языком, потому что на нём удобнее (выразительнее) писать в функциональном стиле.

колбечный-то адище? Конечно пробовал.

"Колбечный адище" не имеет никакого отношения к монадам. Вы пробовали отлаживать код с монадами? Самые распространённые монады - IEnumerable (aka list aka iter) и Nullable (aka maybe aka option).

если у Вас на входе функции данные, а на выходе - вычисление по этим данным и выборке из хранилища, то функция перестаёт быть идемпотентной

Да. Упрощённо программу можно представить в виде "ввод - вычисления - вывод". Логика ввода и вывода обычно простая. Чётко отделяя ввод/вывод от вычислений, мы упрощаем тестирование/сопровождение программы.

Ещё раз:

Почему Вы отказываетесь сравнивать F# и C#?

  • В качестве функционального языка Вы выбрали единственный (в моём списке) чистый. Который не входит в топ-5 функциональных.

  • В качестве императивного языка Вы выбрали единственный (в Вашем списке) язык с АТД. Который не входит в топ-5.

в этой прикладной задаче АДТ не нужен

Да. Для этой задачи достаточно Записи (частный случай АДТ). Такой (или похожий) тип есть во всех популярных языках общего назначения.

задачу в которой он таки нужен Вы не привели

Вы не просили.

вызов кол влияет на производительность

Во-первых, PHP в 10 раз медленнее, чем Haskell, а Вы мне рассказываете про лишний кол, который компилятор может и убрать.

Во-вторых, в Rust функциональный итератор работает так же быстро, как императивный цикл.

test bench_search_for  ... bench:  19,620,300 ns/iter (+/- 915,700)
test bench_search_iter ... bench:  19,234,900 ns/iter (+/- 657,200)

Этого достаточно, чтобы их запрограммировать.

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

Но так же существуют ситуации, где лаконичнее императивные конструкции.

Во всех примерах в этой ветке функциональные конструкции были лаконичнее. Даже код пакмана оказался короче на функциональном языке.

мутабельных счётчиков у вас нет

Чтобы считать, не нужен мутабельный счётчик. 1, 2, 3 - это последовательность. А "[1..10]" выразительнее, чем "for (int i = 0; i < 10; i++);".

Давайте закроем эту тему:

Мы говорим о функции в математике, а Вы мне подсовываете текст про функции в императивных языках программирования.

Rust функционален в той же мере, в какой функционален C++.

В разной: в Rust есть АДТ, а в C++ нет.

в случае с ФЯ у него нет возможности использовать мутабельность.

Вот это - код на функциональном языке:

let x = ref 1
while true do
  if (!x % 4 = 0) then do! break
  printfn "number = %d" !x
  x := !x + 1 

Вот это мутабельная переменная в функциональном языке

let mutable x = 10
x <- 15

При этом отсутствие изменяемых переменных не делает язык хуже.

ну а у пользователя обычных языков возможностей больше чем у Вас

Давайте сравним обычный C# и функциональный F# по количеству возможностей.

я не могу сказать что она делает

Это потому, что Вы не знаете, что такое свёртка (fold - свернуть).

Я даже не вижу длину чего она считает

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

но уже хорошо видно, что читабельности тут ни на грош.

А ещё в немецком языке читабельности ни на грош. Я посмотрел текст - и ничего не понял.

отлаживать не сложнее, а одинаково

Сложнее. Даже просто читать сложнее, так приходится постоянно отвлекаться и заходить внутрь каждой новой функции. Потому что, глядя на вызов функции, я не могу сказать, что она делает. (не меняет ли она состояние).

адепты функциональщины почему-то ещё и против автоматических тестов

HUnit is a unit testing framework for Haskell

Пользователи хотят сохранять файлы на диске и читать их?

Поэтому важно чётко разделять ввод/выод и чистые функции. Чтобы было проще отлаживать.

Отлаживать эти запросы с монадами куда сложнее, нежели с простой императивщиной

Вы пробовали?

ерунда в цикле - становится ерундой помноженной на N

Ерунда и в цикле остаётся ерундой. Потому что имеют значение не абсолютная, а относительная разница.

200 байт - ерунда по сравнению с четырёхмегабайтным объектом. Сто раз по 200 байт - ерунда по сравнению с сотней четырёхмегабайтных объектов.

ну а ерунда в памяти и в цикле становится не только ерундой помноженной на N но и фрагментацией в памяти.

С объектами по 100-200 байт? Нет. В C# уже 10+ лет, как создание/удаление небольших массивов в цикле по производительности не отличается от использования (изменения) одного массива. Когда-то давно - да, приходилось буфер использовать, чтобы в цикле новый массив не создавать.

Вы приводили пример того, что якобы есть на ютубе.

Цитирую: "Предположим, есть сайт с противозаконным опасным для общества контентом." Очевидно, что это не пример конкретного ролика на ютубе.

Хватит юлить.

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

А насчёт замедления я Вам чётко написал, что это незаконно. Поэтому, используя "юлить", Вы искажаете действительность.

И опять конечно без пруфов.

Какой пруф требуется для утверждения "я не буду настаивать, что это правда"?

Ну посмотрите о чем эти сообщения.

" Американское Министерство юстиции подтвердило блокировку 33 иранских сайтов, которые использовались Иранским союзом исламского радио и телевидения (IRTVU), а также трех сайтов, контролируемых группировкой «Катаиб Хезболла», сообщается на сайте ведомства. "

Суть меняется.

Суть не меняется. Суть в том, что некто массово распространяет информацию среди населения. Способ доставки - тв, радио, газета, веб-сайт, объявления на столбах - не принципиален.

Запрета на доступ к какому-нибудь РТ нет.

"RT and state-controlled outlet Sputnik have been blocked in most Western countries since Russia’s military offensive in Ukraine, accused of spreading propaganda "

Если СМИ блокируют за пропаганду, то цензура есть.

И что, отказался?

По утверждению Захаровой, отказался.

До или после судилища с царьградом?

До.

Если я не смотрю ролик, потока нет.

Возможно, я неправильно использую терминологию. Но суть от этого не меняется.

Погуглил.

У меня на первой странице сообщения о блокировках российских и иранских сайтов.

США - вообще не "мировое сообщество".

В любой стране мира, где есть такая техническая возможность, заблокируют сайт с призывом к вооружённому свержению власти и т.п. Если Вы с этим не согласны, то я не буду настаивать, что это правда.

В данном случае решения настолько бред

Бред или не бред, но ютуб нарушает российские законы. Ведь мы же говорим не о справедливости, а о законности.

Блокировка без решения незаконна

Согласен с оговоркой, что по российским законам некоторый контент можно блокировать без решения суда. Я, правда, не помню, какой именно (подходит ли ютуб).

На текущий момент ютуб не заблокирован. Про замедление я уже написал, что незаконно.

Пример не приведете? Я не удивлен.

Напоминаю, что я предложил пример гипотетической страницы, которую обязательно забллокируют.

Но есть проблема: эти штрафы тоже незаконны, у ютуба нет обязанности предоставлять услуги всем подряд.

Я не хочу обсуждать справедливость решений, поэтому написал "с формальной точки зрения".

Есть нарушение закона, есть решение суда. Так что с законностью всё в порядке.

судебное решение пожалуйста покажите

Решение суда по поводу удаления аккаунтов, Вы сами привели. Я уверен, что есть и решения суда по поводу не удаления запрещённых в РФ роликах (статьи Вам уже привели), но искать лень.

1
23 ...

Information

Rating
Does not participate
Registered
Activity