2016-12-13 2 views
3

Я свежий для Haskell, и я пытаюсь понять язык, написав код. Я знаком с очень простыми инструкциями по ghci: head, tail, sum, (*) и т. П. - очень просто.Что имеет вид «Ограничение» в Haskell

Функция, которую я пытаюсь сделать, предназначена для решения теоремы Пифагора для векторов любого числа измерений. Это выглядит примерно так: квадратный корень (a^2 + b^2 + c^2 ...)

Что я могу сделать в ghci в нескольких строках, которые я пытаюсь сделать функцией, следующее :

sq x = x*x 

b = map sq [1,2,3] 

a = sum b 

x = sqrt b 

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

mod :: [Num a] => a 
mod x = sqrt a 
    where a = sum [b] 
      where [b] = map sq [x] 

Я не понимаю этот вопрос, когда я пытаюсь запустить его:

Expected a constraint, but ‘[Num a]’ has kind ‘*’ 
    • In the type signature: 
     Main.mod :: [Num a] => a 

ответ

9

Несколько вещей, чтобы отрегулировать:

0) mod не хорошее имя для функции, так как это имя функции по модулю из стандартной библиотеки. Вместо этого я назову его norm.

1) Тип подписи вы имели в виду написать это:

norm :: Num a => [a] -> a 

[a] тип списка с элементами типа a. Num a до => не является типом, а ограничение, в котором указано, что a должен быть типом числа (или, точнее, что он должен быть экземпляром класса Num). [Num a] => приводит к ошибке, которую вы видели, потому что, учитывая квадратные скобки, средство проверки типов берет его как попытку использовать тип списка вместо ограничения.

Из-за проблемы Num a вы не указали тип результата из подписи. Исправленная подпись отражает, что ваша функция принимает список чисел и возвращает число.

2) Ограничение Num a слишком слабо для того, что вы пытаетесь сделать. Для того, чтобы использовать sqrt, вам нужно иметь не просто тип номера, но тот, который является экземпляром Floating (комментарий см leftaroundabout на этот ответ):

GHCi> :t sqrt 
sqrt :: Floating a => a -> a 

Таким образом, ваша подпись должна быть

norm :: Floating a => [a] -> a 

3) [x] - это список с одним элементом, x. Если ваш аргумент уже является списком, как говорит подпись типа, нет необходимости заключать его в квадратные скобки. Ваша функция, то становится:

norm :: Floating a => [a] -> a 
norm x = sqrt a 
    where a = sum b 
      where b = map sq x 

Или, более аккуратно, без второго where -блока:

norm :: Floating a => [a] -> a 
norm x = sqrt (sum b) 
    where b = map sq x 
+1

FTR: несмотря на название, 'Floating' это на самом деле не«класс чисел с плавающей точкой», которая была бы' RealFloat' (или даже ['IEEE'] (http://hackage.haskell.org/package/ieee754-0.7.9/docs/Numeric-IEEE.html#t:IEEE)). Это довольно просто класс типов _number, которые вы можете делать с помощью calculus with_, также позволяя использовать такие вещи, как точная реальная арифметика. – leftaroundabout

+0

@leftaroundabout Спасибо, что выделили это; неточное заявление удалено. – duplode

0

Короткий ответ заключается в том, что [Num a] не является ограничением. Вы должны написать (Num a) или просто Num a.

От Haskell 2010 Language Report

4.1.3 Синтаксис класса Assertions и контексты

context → class 
    | (class1 , … , classn)   (n ≥ 0) 
class → qtycls tyvar 
    | qtycls (tyvar atype1 … atypen) (n ≥ 1) 
qtycls → [ modid . ] tycls 
tycls → conid 
tyvar → varid 

Класс утверждение имеет вид qtyclstyvar, и указывает на принадлежность к типу tyvar в классе qtycls. Идентификатор класса начинается с буквы верхнего регистра. контекст состоит из нуля или более утверждений класса и имеет общий вид (C1 u1, ..., Cn ип), где C1, ..., Cn являются идентификаторы класса, и каждый из u1, ..., ип - это либо переменная типа, либо применение переменной типа к одному или нескольким типам. Внешние круглые скобки могут быть опущены, когда n = 1. В общем, мы используем се для обозначения контекста и мы пишем сх => т указать тип т ограничен контекстом сх. Контекст cx должен содержать только переменные типа, указанные в t. Для удобства мы пишем cx => t, даже если контекст cx пуст, хотя в этом случае конкретный синтаксис не содержит =>.

4

Как вы знаете, значения могут быть классифицированы по их типу. "foo" имеет тип [Char], Just 'c' имеет тип Maybe Char и т.д.

Аналогично, типы могут быть классифицированы по их любезного. Все конкретные типы, для которых вы можете предоставить значение, имеют вид *. Вы можете увидеть это с помощью команды :k в GHCi:

> :k Int 
Int :: * 
> :k Maybe Int 
Maybe Int :: * 

Конструкторы типов также имеют виды. Они являются, по сути, функциями типа, поэтому их виды аналогичны регулярным функциям.

> :t id 
id :: a -> a 
> :k Maybe 
Maybe :: * -> * 

Но что такое Num a? Это не тип, поэтому он не имеет вида *. Это не конструктор типов, поэтому он не имеет типа стрелки. Это нечто новое, поэтому для его описания был создан новый вид.

> :k Num Int 
Num Int :: Constraint 

И сам Num является Constraint значной функции: она принимает значение любезного * и производит Constraint:

> :k Num 
Num :: * -> Constraint 

Вещи с любезным Constraint используется, чтобы указать, что класс типов конкретного тип должен быть экземпляром. Это значение, которое может произойти до => в сигнатуре типа. Это также «аргумент» в «функции» instance:

instance Num Int where 
    ... 
Смежные вопросы