2016-11-27 4 views
0

Мой вопрос возник при чтении учебника Functors, Applicatives, And Monads In Pictures и его JavaScript version.Monad "unboxing"

Когда текст говорит о том, что functor разворачивает значение из контекста, я понимаю, что происходит трансформация Just 5 ->5. Согласно What does the "Just" syntax mean in Haskell?, Just «определено в области» для монады Maybe.

Мой вопрос в том, что так волшебно относится ко всей разворачивающейся вещи? Я имею в виду, в чем проблема наличия некоторого языкового правила, которое автоматически разворачивает «скопированные» переменные? Мне кажется, что это действие - это просто поиск в какой-то таблице, где символ Just 5 соответствует целому числу 5.

Мой вопрос основан на версии JavaScript, где Just 5 является экземпляром экземпляра прототипа. Так что разворачивание - это вообще не ракетостроение.

Является ли это причиной «для вычисления» причины или для «программиста»? Почему мы различаем Just 5 от 5 на уровне программирования?

ответ

7

Прежде всего, я не думаю, что вы можете понять монады и тому подобное, не понимая Haskell как системы типа (т.е. без изучения языка, как Haskell) , Да, есть много учебников, которые утверждают иначе, но я прочитал их много, прежде чем изучать Haskell, и я не понял. Поэтому мой совет: если вы хотите понять, что Монады учатся хотя бы Хаскелу.

На ваш вопрос: «Почему мы отлишаем Just 5 от 5 на уровне программирования?». Для безопасности типов. В большинстве языков, которые не являются Haskell null, nil, whatever, часто используется для представления отсутствия значения. Это часто приводит к таким вещам, как NullPointerExceptions, потому что вы не ожидали, что значение может быть не там.

В Haskell нет null. Поэтому, если у вас есть значение типа Int или что-то еще, это значение не может быть null. Вы гарантируете, что есть ценность. Большой! Но иногда вам действительно нужно/нужно кодировать отсутствие значения. В Haskell мы используем для этого Maybe. Итак, что-то типа Maybe Int может быть чем-то вроде Just 5 или Nothing.Таким образом, явное, что значение может быть не там, и вы не можете случайно забыть, что это может быть Nothing, потому что вы должны явно развернуть значение.

Это не имеет ничего общего с Monads, за исключением того, что Maybe реализует класс типа Monad (класс типа немного похож на интерфейс Java, если вы знакомы с Java). Это возможно, это не прежде всего Монада, а просто случается, что это тоже Монада.

2

Что такое «разворот», зависит от контейнера. Maybe - всего лишь один пример. «Развертывание» означает что-то совершенно другое, когда контейнер [] вместо Maybe.

Волшебное о всей разворачивающейся вещи - это абстракция: в Монаде мы имеем понятие «разворачивания», которое абстрагирует природу контейнера; а затем он начинает получать «волшебный» ...

Вы спрашиваете, что Just означает: Просто нет ничего, кроме конструктора в Haskell Тип данных, определенной с помощью декларации данных, как:

data Maybe a = Just a | Nothing 

Just принимать значение тип a и создает значение типа Maybe a. Это способ Haskell для distinguigh значения типа a из значений типа Maybe a

4

Возможный пример: рассмотрим тип Haskell Maybe (Maybe Int). Его значение может быть следующего вид

  • Nothing
  • Just Nothing
  • Just (Just n) для некоторых целого n

без Just обертки мы не могли различить между двумя первыми.

Действительно, вся точка необязательного типа Maybe a заключается в том, чтобы добавить новое значение (Nothing) к существующему типу a. Чтобы гарантировать, что Nothing действительно является новым значением, мы переносим другие значения внутри Just.

Это также помогает во время вывода типа. Когда мы видим вызов функции f 'a', мы видим, что f вызывается у типа Char, а не у типа Maybe Char или Maybe (Maybe Char). Система typeclass позволяла бы f иметь различную реализацию в каждом из этих случаев (это похоже на «перегрузку» на некоторых языках ООП).

5

Я думаю, вы смотрите на это с неправильного направления. Monad явно не об развертке. Monad - о составе.

Он позволяет комбинировать (необязательно применять) функцию типа a -> m b со значением типа m a, чтобы получить значение типа m b. Я могу понять, где вы думаете, что очевидный способ сделать это - разворачивать значение типа m a в значение типа a. Но очень мало Monad экземпляров работают так. Фактически, единственными, которые могут работать таким образом, являются те, которые эквивалентны типу Identity. Для почти всех экземпляров Monad просто невозможно развернуть значение.

Рассмотрите Maybe. Развертывание значения типа Maybe a в значение типа a невозможно, когда начальное значение равно Nothing. Монадическая композиция должна делать что-то более интересное, чем просто разворачивание.

Рассмотрите []. Развертывание значения типа [a] в значение типа a невозможно, если только вход не является списком длины 1. В каждом другом случае монадическая композиция делает что-то более интересное, чем разворачивание.

Рассмотрите IO. Значение, подобное getLine :: IO String, не содержит значения String. Это невозможно разобрать, потому что это не что-то обертывает. Монадический состав значений IO ничего не разворачивает.Он объединяет значения IO в более сложные значения IO.

Я думаю, что стоит настроить вашу точку зрения на то, что означает Monad. Если бы это был только разворачивающийся интерфейс, это было бы бесполезно. Это, однако, более тонко. Это композиционный интерфейс.

1

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

Итак, ваш вопрос можно перефразировать как: Почему нет неявного преобразования Just 5 => 5? Но ответ очень прост. Потому что значение Just 5 имеет тип Maybe Integer, поэтому это значение может быть Nothing, но что должен делать компилятор в этом случае? Только программист может решить эту ситуацию.

Но есть более неудобный вопрос. Существуют типы, например, newtype Identity a = Identity a. Это просто обертка вокруг некоторой ценности. Итак, почему нет конверсии impliciti Identity a => a?

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

2

Мой вопрос в том, что такое волшебство в отношении всей разворачивающейся вещи?

В этом нет ничего волшебного. Вы можете использовать Разнообразное сопоставления с образцом (здесь в форме выражения case) для определения ...

mapMaybe :: (a -> b) -> Maybe a -> Maybe b 
mapMaybe f mx = case mx of 
    Just x -> Just (f x) 
    _ -> mx 

... которая точно так же, чем fmap для Maybe. Единственное, что добавляет класс Functor - и это очень полезная вещь, не ошибитесь - это дополнительный уровень абстракции, который охватывает различные структуры, которые можно сопоставить.

Почему мы отлишаем Just 5 от 5 на уровне программирования?

Более значимым, чем различие между Just 5 и 5 является один между их типов - например, между Maybe Int и Int. Если у вас есть x :: Int, вы можете быть уверены, что x - это стоимость Int, с которой вы можете работать. Однако, если у вас есть mx :: Maybe Int, у вас нет такой уверенности, поскольку может отсутствовать Int (т. Е. mx может быть Nothing), и система типов заставляет вас признать и разрешить эту возможность.

Смотрите также: jpath's answer для дальнейших замечаний относительно полезности Maybe (которое не обязательно привязано к классам, таким как Functor и Monad); Carl's answer для дальнейших комментариев относительно полезности таких классов, как Functor и Monad (за пределами примера Maybe).