Haskell: разрешение отправки для исправления класса типов - PullRequest
1 голос
/ 28 декабря 2011

Я немного смущен тем, как Haskell отправляет правильную функцию в классе типов.Это сделано неявно, или это как-то связано с тем, как Haskell определяет тип чего-либо?Например, рассмотрим следующее:

instance Monad Parser where
     return a = Parser (\ cs -> [(a, cs)])

Если я сделаю что-то вроде:

return something >>= \x -> -- Returning a parser!

Угадает ли haskell, какой возврат к вызову выполняется с правой стороны привязки?Как он узнает, что вызов Parser return, а не какой-то другой?

Edit:

Хорошо, так что на самом деле это вызывает у меня больше вопросов.Я понял, как Haskell может определить, какой должен быть «возврат», решая объявления типов.Однако что делать в случае совершенно неоднозначного утверждения?

Например, что если я открою интерпретатор и введу return 1?Как он узнает, кто вернулся, чтобы позвонить тогда?

Ответы [ 3 ]

4 голосов
/ 28 декабря 2011

Это верно - Haskell может отправлять по типу возврата. Фактически, поскольку Haskell является функциональным языком, не существует строгого понятия «возвращаемый тип». Например, Int в (Bool -> Int) -> String тип возврата?

Итак, как это происходит? Во-первых, Haskell определяет тип выражения. Имеет форму

forall x1 x2 [...] . Ctx => t

где Ctx является контекстом и имеет вид (Class1 vars1, Class2 vars2, ...).

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

В частности, в вашем случае Haskell знает, что оператор связывания >>= имеет тип

m a -> (a -> m b) -> m b.

Поскольку правый операнд имеет тип Parser b для некоторых b, переменная m должна быть Parser, поэтому return имеет тип a -> Parser a.

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

Е.Г.

show (read "blah")

имеет тип String, но для оценки необходимо выбрать несколько экземпляров классов Read и Show.

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

1 голос
/ 28 декабря 2011

«return 1» обрабатывается ghc и ghci с помощью небольшой команды см. На Haskell «default».

Это удобство формально задокументировано в отчете Haskell 98 здесь . Декларация «по умолчанию» в Prelude, которую вы можете переопределить:

default (Integer,Double)

Назначение «по умолчанию» состоит в том, чтобы то, что создает тип, являющийся экземпляром «Num», не требовало явной аннотации типа в наиболее распространенных ситуациях. Значение вышеупомянутого объявления «по умолчанию» заключается в том, что компилятор сначала пытается использовать тип Integer, а затем тип Double. Первый тип для правильной компиляции выбран. Это можно полностью отключить, написав:

default ()

Или вы можете составить список со своими подсказками для компилятора, но стандарт ограничивает вас перечислением только тех типов, которые определены в Prelude или иным образом явно разрешены вашим компилятором. Таким образом, вам не гарантировано право перечислять новые типы данных в объявлении «по умолчанию».

С GHC правила по умолчанию находятся в разделе 2.4.5 руководства пользователя . GHC всегда позволяет вам использовать ваши новые типы «Num» в «default». Кроме того, включив расширение языка «ExtendedDefaultRules», объявление «default» может дать значения по умолчанию для экземпляров «Show», «Eq» и «Ord». Простой пример для Num:

module Main where

data K = K deriving (Show,Eq,Ord)

instance Num K where fromInteger _ = K

default (K)

main = print 0

При запуске в ghci печатается буква "K"

0 голосов
/ 28 декабря 2011

Например, что если я открою интерпретатор и введу return 1?

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

Как он узнает, кто вернулся, чтобы позвонить тогда?

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

return 1 :: Maybe Int
...