Yo может получить URL-адрес favicon с HTML-сайта веб-сайта.
Вот тег favicon:
<link rel="icon" type="image/png" href="/someimage.png" />
Здесь вы должны использовать регулярное выражение. Если тег не найден, найдите «favicon.ico» в корневом каталоге сайта. Если ничего не найдено, на сайте нет значка.
Самое простое объяснение, о котором я могу думать, состоит в том, что монады являются способом составить функции с украшенными результатами (иначе состав Kleisli). Функция "embelished" имеет подпись a -> (b, smth)
, где a
и b
типы (думайте Int
, Bool
), который мог бы отличаться друг от друга, но не обязательно - и smth
"контекст" или "embelishment".
Этот тип функций может также быть записан a -> m b
, где m
эквивалентно "embelishment" smth
. Таким образом, это функции, которые возвращают значения в контексте (думайте функции, которые регистрируют их действия, где smth
регистрирующееся сообщение; или функции, которые выполняют input\output и их результаты, зависят от результата действия IO).
монада А является интерфейсом ("typeclass"), который заставляет реализатора сказать ее, как составить такие функции. Реализатор должен определить функцию состава (a -> m b) -> (b -> m c) -> (a -> m c)
для любого типа m
, который хочет реализовать интерфейс (это - состав Kleisli).
Так, если мы говорим, что у нас есть тип "кортеж" (Int, String)
результаты представления вычислений на [1 113] с, которые также регистрируют их действия, с [1 114] являющийся "embelishment" - журналом действия - и двумя функциями increment :: Int -> (Int, String)
и twoTimes :: Int -> (Int, String)
, мы хотим получить функцию incrementThenDouble :: Int -> (Int, String)
, который является составом двух функций, который также принимает во внимание журналы.
На данном примере, реализация монады двух функций относится к целочисленному значению 2 incrementThenDouble 2
(который равен [1 119]), возвратился бы (6, " Adding 1. Doubling 3.")
для посреднических результатов increment 2
равный [1 122] и twoTimes 3
равный [1 124]
От этой функции состава Kleisli, можно получить обычные одноместные функции.
Из википедии :
В функциональном программировании монада - это своего рода абстрактный тип данных, используемый для представляют вычисления (вместо данных в модели предметной области). Монады позволяют программисту связывать действия вместе для построения конвейера, в котором каждое действие украшается дополнительными правилами обработки, предоставленными монада. Программы, написанные в функциональном стиле , могут использовать монады для структурирования процедур, которые включают в себя последовательные операции, 1 [2] , или для определения произвольных потоков управления {{1} } (например, обработка параллелизма, продолжений или исключений).
Формально монада конструируется путем определения двух операций (связывания и возврата) и конструктора типа M, который должен выполнять несколько свойств, чтобы разрешить правильная композиция монадических функций (т. е. функций, которые используют значения из монады в качестве своих аргументов). Операция возврата берет значение из простого типа и помещает его в монадический контейнер типа M. Операция связывания выполняет обратный процесс , извлекая исходное значение из контейнера и передача его связанной следующей функции в конвейере.
Программист будет составлять монадические функции для определения конвейера обработки данных .Монада действует как структура , поскольку это многократно используемое поведение , которое определяет порядок, в котором вызываются определенные монадические функции в конвейере , и управляет вся работа под прикрытием, необходимая для вычисления . [3] Операторы связывания и возврата , чередующиеся в конвейере , будут выполняться после того, как каждая монадическая функция вернет управление, и позаботятся о конкретных аспектах {{1 }} обрабатывается монадой.
Я считаю, что это очень хорошо объясняет.
Если вы когда-либо использовали Powershell, шаблоны, описанные Эриком, должны звучать знакомо. Командлеты Powershell являются монадами; функциональный состав представлен конвейером.
Интервью Джеффри Сновера с Эриком Мейером более подробное.
ОБНОВЛЕНИЕ. Этот вопрос был предметом очень длинной серии блогов, которую вы можете прочитать по адресу Monads - спасибо за отличный вопрос!
В терминах, понятных программисту ООП (без какого-либо опыта функционального программирования), что такое монада?
Монада - это «усилитель» типов , подчиняющихся определенным правилам и , в котором предусмотрены определенные операции .
Во-первых, что такое «типовой усилитель»? Под этим я подразумеваю некоторую систему, которая позволяет вам взять тип и превратить его в более особенный тип. Например, в C # рассмотрим Nullable
. Это типовой усилитель. Он позволяет вам взять тип, например int
, и добавить к этому типу новую возможность, а именно, что теперь он может иметь значение NULL, хотя раньше не мог.
В качестве второго примера рассмотрим IEnumerable
. Это усилитель типов. Он позволяет вам взять тип, скажем, string
, и добавить к этому типу новую возможность, а именно, что теперь вы можете создавать последовательность строк из любого количества отдельных строк.
Каковы «определенные правила»? Вкратце, существует разумный способ для функций базового типа работать с усиленным типом, чтобы они следовали обычным правилам функциональной композиции. Например, если у вас есть функция для целых чисел, скажем
int M(int x) { return x + N(x * 2); }
, тогда соответствующая функция на Nullable
может заставить все операторы и вызовы работать вместе «таким же образом», как и они. до.
(Это невероятно расплывчато и неточно; вы попросили объяснение, которое не предполагает ничего о знании функционального состава.)
Что такое «операции»?
Существует «единичная» операция (иногда ошибочно называемая операцией «возврата»), которая берет значение из простого типа и создает эквивалентное монадическое значение. По сути, это дает возможность взять значение неусиленного типа и превратить его в значение усиленного типа. Он может быть реализован как конструктор на языке объектно-ориентированного программирования.
Существует операция «связывания», которая принимает монадическое значение, и функция, которая может преобразовывать значение, и возвращает новое монадическое значение. Связывание - это ключевая операция, определяющая семантику монады. Это позволяет нам преобразовывать операции с неусиленным типом в операции с усиленным типом, которые подчиняются упомянутым выше правилам функциональной композиции.
Часто есть способ вернуть неусиленный тип из усиленного. Строго говоря, для монады эта операция не требуется. (Хотя это необходимо, если вы хотите иметь комонаду . Мы не будем рассматривать их далее в этой статье.)
Снова возьмем Nullable
в качестве примера . Вы можете превратить int
в Nullable
с помощью конструктора.Компилятор C # позаботится о самом «подъеме», допускающем значение NULL, но если этого не произошло, преобразование подъема будет простым: операция, скажем,
int M(int x) { whatever }
преобразуется в
Nullable<int> M(Nullable<int> x)
{
if (x == null)
return null;
else
return new Nullable<int>(whatever);
}
и превращение Nullable
обратно в int
выполняется с помощью свойства Value
.
Ключевым битом является преобразование функции. Обратите внимание, как фактическая семантика операции, допускающей значение NULL, - что операция с NULL
распространяет NULL
, - фиксируется в преобразовании. Мы можем обобщить это.
Предположим, у вас есть функция от int
до int
, как наш оригинальный M
. Вы можете легко превратить это в функцию, которая принимает int
и возвращает Nullable
, потому что вы можете просто запустить результат через конструктор, допускающий значение NULL. Теперь предположим, что у вас есть этот метод высшего порядка:
static Nullable<T> Bind<T>(Nullable<T> amplified, Func<T, Nullable<T>> func)
{
if (amplified == null)
return null;
else
return func(amplified.Value);
}
Посмотрите, что вы можете с ним сделать? Любой метод, который принимает int
и возвращает int
или принимает int
и возвращает Nullable
может теперь к нему применена семантика, допускающая обнуление .
Кроме того: предположим, что у вас есть два метода
Nullable<int> X(int q) { ... }
Nullable<int> Y(int r) { ... }
, и вы хотите их составить:
Nullable<int> Z(int s) { return X(Y(s)); }
То есть Z
- это композиция X
и Y
. Но вы не можете этого сделать, потому что X
принимает int
, а Y
возвращает Nullable
. Но поскольку у вас есть операция "связывания", вы можете выполнить эту работу:
Nullable<int> Z(int s) { return Bind(Y(s), X); }
Операция связывания монады - это то, что заставляет работать композицию функций для усиленных типов. «Правила», о которых я говорил выше, состоят в том, что монада сохраняет правила нормальной композиции функций; что композиция с функциями идентичности приводит к исходной функции, эта композиция ассоциативна и т. д.
В C # Bind называется SelectMany. Посмотрите, как это работает с монадой последовательности. Нам нужны две вещи: превратить значение в последовательность и связать операции с последовательностями. В качестве бонуса у нас также есть «превратить последовательность обратно в значение».Вот эти операции:
static IEnumerable<T> MakeSequence<T>(T item)
{
yield return item;
}
// Extract a value
static T First<T>(IEnumerable<T> sequence)
{
// let's just take the first one
foreach(T item in sequence) return item;
throw new Exception("No first item");
}
// "Bind" is called "SelectMany"
static IEnumerable<T> SelectMany<T>(IEnumerable<T> seq, Func<T, IEnumerable<T>> func)
{
foreach(T item in seq)
foreach(T result in func(item))
yield return result;
}
Правило монады, допускающей значение NULL, заключалось в том, чтобы «объединить две функции, которые производят значения NULL, вместе, проверить, приводит ли внутренняя функция к NULL; если да, то произвести NULL, если нет, то вызвать внешнюю. с результатом ». Это желаемая семантика nullable.
Правило монады последовательностей состоит в том, чтобы «объединить две функции, которые производят последовательности вместе, применить внешнюю функцию к каждому элементу, произведенному внутренней функцией, а затем объединить все результирующие последовательности вместе». Фундаментальная семантика монад зафиксирована в методах Bind
/ SelectMany
; это метод, который сообщает вам, что на самом деле означает монада .
Мы можем сделать даже лучше. Предположим, у вас есть последовательность целых чисел и метод, который принимает целые числа и выдает последовательности строк. Мы могли бы обобщить операцию связывания, чтобы разрешить композицию функций, которые принимают и возвращают различные усиленные типы, при условии, что входы одного совпадают с выходами другого:
static IEnumerable<U> SelectMany<T,U>(IEnumerable<T> seq, Func<T, IEnumerable<U>> func)
{
foreach(T item in seq)
foreach(U result in func(item))
yield return result;
}
Итак, теперь мы можем сказать «усилить эту группу отдельных целых чисел в последовательность целых чисел. Преобразуйте это конкретное целое число в связку строк, усиленную до последовательности строк. Теперь соедините обе операции вместе: увеличьте эту связку целых чисел до конкатенации всех последовательностей строк ». Монады позволяют вам составлять ваши амплификации.
Какую проблему он решает и в каких наиболее распространенных местах он используется?
Это похоже на вопрос: «Какие проблемы решает одноэлементный шаблон?», Но я попробую.
Монады обычно используются для решения таких проблем, как:
C # использует монады в своем дизайне. Как уже упоминалось, шаблон, допускающий значение NULL, очень похож на «возможно монаду». LINQ полностью построен из монад; метод SelectMany
выполняет семантическую работу по композиции операций. (Эрик Мейер любит указывать на то, что каждая функция LINQ может быть реализована с помощью SelectMany
; все остальное - просто удобство.)
Чтобы прояснить то понимание, которое я искал, допустим, вы преобразовывали приложение FP, которое имело монады, в приложение ООП. Что бы вы сделали, чтобы перенести обязанности монад в приложение ООП?
Большинство языков ООП не имеют достаточно богатой системы типов, чтобы напрямую представлять сам образец монады; вам нужна система типов, которая поддерживает типы более высокого уровня, чем универсальные типы. Так что я бы не стал этого делать.Скорее, я бы реализовал общие типы, которые представляют каждую монаду, и реализовал бы методы, которые представляют три необходимые вам операции: преобразование значения в усиленное значение, (возможно) преобразование усиленного значения в значение и преобразование функции на неусиленных значениях в функция от усиленных значений.
Хорошее место для начала - то, как мы реализовали LINQ в C #.Изучите метод SelectMany
; это ключ к пониманию того, как монада последовательности работает в C #. Это очень простой метод, но очень мощный!
Предлагается для дальнейшего чтения:
Монада - это тип данных, который инкапсулирует значение и к которому, по сути, могут применяться две операции:
return x
создает значение типа монады, которое инкапсулирует x
m >> = f
(читается как «оператор связывания») применяет функцию f
к значению в монаде m
Вот что такое монада. Есть еще несколько технических деталей , но в основном эти две операции определяют монаду. Настоящий вопрос: «Что делает монада ?», И это зависит от монады: списки - это монады, Maybes - это монады, операции ввода-вывода - это монады. Когда мы говорим, что эти объекты являются монадами, это означает только то, что они имеют интерфейс монад return
и >> =
.
Я бы сказал, что ближайшей OO-аналогией монадам является "командный паттерн".
В командном шаблоне вы оборачиваете обычный оператор или выражение в объект command. Объект command раскрывает метод execute, который выполняет обернутый оператор. Таким образом, оператор превращается в объект первого класса, который можно передавать и выполнять по своему усмотрению. Команды могут быть составлены, так что вы можете создать программу-объект путем цепочки и вложенности команд-объектов.
Команды выполняются отдельным объектом, инвокер. Преимущество использования шаблона команд (а не просто выполнения серии обычных операторов) заключается в том, что разные инвокеры могут применять различную логику к тому, как должны выполняться команды.
Шаблон команд может быть использован для добавления (или удаления) возможностей языка, которые не поддерживаются основным языком. Например, в гипотетическом ОО-языке без исключений можно добавить семантику исключений, открыв командам методы "try" и "throw". Когда команда вызывает throw, вызывающий возвращается назад по списку (или дереву) команд до последнего вызова "try". И наоборот, вы можете удалить семантику исключений из языка (если вы считаете, что исключения - это плохо), перехватывая все исключения, вызванные каждой отдельной командой, и превращая их в коды ошибок, которые затем передаются следующей команде.
Даже более причудливые семантики выполнения, такие как транзакции, недетерминированное выполнение или продолжения, могут быть реализованы подобным образом в языке, который не поддерживает их изначально. Это довольно мощный паттерн, если задуматься.
В реальности паттерны команд не используются как общая особенность языка. Накладные расходы на превращение каждого оператора в отдельный класс привели бы к невыносимому количеству кодового шаблона. Но в принципе он может быть использован для решения тех же проблем, для решения которых в fp используются монады.
У вас есть недавняя презентация « Monadologie - профессиональная помощь при типовой тревоге » от Christopher League (12 июля 2010 г.), которая вполне интересно по темам продолжения и монады.
Видео, сопровождающее эту (показ слайдов) презентации, на самом деле доступно на vimeo .
Часть Monad начинается примерно через 37 минут в этом часовом видео и начинается со слайда 42 из 58 слайд-презентации.
Он представлен как «ведущий шаблон проектирования для функционального программирования», но в примерах используется язык Scala, который одновременно является ООП и функциональным.
Вы можете узнать больше о монаде в Scala в сообщении блога « Монады - Другой способ абстрактных вычислений в Scala » из Дебасиша Гоша (27 марта 2008 г.).
Конструктор типа M является монадой, если он поддерживает следующие операции:
# the return function
def unit[A] (x: A): M[A]
# called "bind" in Haskell
def flatMap[A,B] (m: M[A]) (f: A => M[B]): M[B]
# Other two can be written in term of the first two:
def map[A,B] (m: M[A]) (f: A => B): M[B] =
flatMap(m){ x => unit(f(x)) }
def andThen[A,B] (ma: M[A]) (mb: M[B]): M[B] =
flatMap(ma){ x => mb }
Так, например (в Scala):
Option
- это монада def unit[A] (x: A): Option[A] = Some(x) def flatMap[A,B](m:Option[A])(f:A =>Option[B]): Option[B] = m match { case None => None case Some(x) => f(x) }
List
is Monad def unit[A] (x: A): List[A] = List(x) def flatMap[A,B](m:List[A])(f:A =>List[B]): List[B] = m match { case Nil => Nil case x::xs => f(x) ::: flatMap(xs)(f) }
Монада имеет большое значение в Scala из-за удобного синтаксиса, созданного для использования преимуществ структур Monad:
для
понимания в Scala :
for {
i <- 1 to 4
j <- 1 to i
k <- 1 to j
} yield i*j*k
транслируется компилятором в:
(1 to 4).flatMap { i =>
(1 to i).flatMap { j =>
(1 to j).map { k =>
i*j*k }}}
] Ключевой абстракцией является flatMap
, которая связывает вычисления посредством цепочки.
Каждый вызов flatMap
возвращает один и тот же тип структуры данных (но с другим значением), который служит входными данными для следующей команды в цепочке.
В приведенном выше фрагменте flatMap принимает в качестве входных данных замыкание (SomeType) => List [AnotherType]
и возвращает List [AnotherType]
. Важно отметить, что все плоские карты принимают один и тот же тип замыкания в качестве входных и возвращают тот же тип в качестве выходных.
Это то, что «связывает» вычислительный поток - каждый элемент последовательности в for-computing должен соблюдать это ограничение типа.
Если вы выполните две операции (которые могут потерпеть неудачу) и передадите результат третьей, например:
lookupVenue: String => Option[Venue]
getLoggedInUser: SessionID => Option[User]
reserveTable: (Venue, User) => Option[ConfNo]
, но без использования преимуществ Monad, вы получите запутанный ООП-код, например:
val user = getLoggedInUser(session)
val confirm =
if(!user.isDefined) None
else lookupVenue(name) match {
case None => None
case Some(venue) =>
val confno = reserveTable(venue, user.get)
if(confno.isDefined)
mailTo(confno.get, user.get)
confno
}
, тогда как с Monad вы можете работайте с фактическими типами ( Venue
, User
), как и все операции, и держите элементы проверки Option скрытыми, все из-за плоских карт синтаксиса for:
val confirm = for {
venue <- lookupVenue(name)
user <- getLoggedInUser(session)
confno <- reserveTable(venue, user)
} yield {
mailTo(confno, user)
confno
}
Часть yield будет выполнена, только если все три функции имеют Some [X]
; любой Нет
не будет напрямую возвращен на подтверждение
.
Итак:
Монады позволяют выполнять упорядоченные вычисления в рамках функционального программирования, что позволяет нам моделировать последовательность действий в красивой структурированной форме, наподобие DSL.
И самая большая сила заключается в способности составлять монады, которые служат разным целям, в расширяемые абстракции внутри приложения.
Это упорядочение и распараллеливание действий монадой осуществляется компилятором языка, который выполняет преобразование с помощью магии замыканий.
Между прочим, Монада - это не только модель вычислений, используемая в FP:
Теория категорий предлагает множество моделей вычислений. Среди них
- Модель вычислений Стрелка
- Модель вычислений Монада
- Аппликативная модель вычислений
В терминах, которые программист ООП мог бы понять (без функционала фон программирования), что такое монада?
Какую проблему он решает и что наиболее часто ли она используется? наиболее часто ли она используется?
С точки зрения объектно-ориентированного программирования, монада - это интерфейс (или, что более вероятно, миксин), параметризованный типом с двумя методами, return
и bind
, которые описывают:
Он решает проблему того же типа, что и любой интерфейс, а именно: «У меня есть несколько разных классов, которые делают разные вещи, но, кажется, делают эти разные вещи таким образом, который имеет внутреннее сходство. Как я могу описать это сходство между ними, даже если сами классы на самом деле не являются подтипами чего-либо? ближе, чем сам класс Object? »
Более конкретно, Monad
« interface »похож на IEnumerator
или IIterator
в том, что он принимает тип, который сам принимает тип. Однако основной «точкой» Монады
является возможность соединять операции на основе внутреннего типа, вплоть до появления нового «внутреннего типа», сохраняя - или даже улучшая - информационную структуру основной класс.