Почему вы можете создать ценность с помощью Just (+)?

В настоящее время я изучаю Haskell и застрял на создании экземпляров типов в классы типов. Я вообще-то не понимаю, почему можно создать значение типа Maybe a с помощью Just (+).

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

Помня об этом, следующий код не должен быть компилируемым или исполняемым, поскольку функция не является частью класса типов Eq:

let a = Just (+)
let b = Just (-)

Но на самом деле GHCi выполняет код, не выдавая сообщения об ошибке. Если вы затем попытаетесь сравнить эти два значения (что также не должно быть возможным), интерпретатор выдаст следующее сообщение об ошибке:

a == b

<interactive>:24:1: error:
    * No instance for (Eq (Integer -> Integer -> Integer))
        arising from a use of `=='
        (maybe you haven't applied a function to enough arguments?)
    * In the expression: a == b
      In an equation for `it': it = a == b

Эта проблема также возникает, если вы создаете свой собственный тип Maybe a.


person Daniel    schedule 05.08.2019    source источник
comment
Как вы думаете, почему let a = Just (+) должно быть ошибкой? Это значение типа Maybe (Integer -> Integer -> Integer) - что в этом плохого? Вы не можете сравнивать a==b, конечно, но вы также не можете сравнивать (+)==(-), но я думаю, что вы в порядке с существующим (+). Если (+) существует, почему Just (+) следует запретить?   -  person chi    schedule 05.08.2019


Ответы (1)


Экземпляр Eq для Maybe в конечном итоге выглядит так (то есть deriving (Eq) по существу переписывается в это):

instance (Eq a) => Eq (Maybe a) where
    ...

Это можно прочитать как если a является членом Eq, то то же самое и Maybe a. Так что совершенно нормально сделать Maybe (Int -> Int) или что у вас есть, просто не будет Eq, если его аргумент не будет.

Более удобный способ думать об этом, больше с точки зрения компилятора: чтобы решить ограничение Eq (Maybe a), достаточно решить ограничение Eq a. Итак, когда мы говорим

a == b

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

person luqui    schedule 05.08.2019