2016-12-13 13 views
3

Ich bin frisch zu Haskell und ich versuche, die Sprache zu verstehen, indem Sie einen Code schreiben. Ich bin nur vertraut mit sehr einfachen Anweisungen auf ghci: Kopf, Schwanz, Summe, (*) und dergleichen - sehr einfach.Was hat Art "Constraint" bedeutet in Haskell

Die Funktion, die ich versuche, ist, Pythagoras 'Theorem für Vektoren einer beliebigen Anzahl von Dimensionen zu lösen. Das sieht ungefähr so ​​aus: Quadratwurzel (a^2 + b^2 + c^2 ...)

Was ich in ghci in ein paar Zeilen machen kann, was ich versuche, eine Funktion zu machen, ist die folgende :

sq x = x*x 

b = map sq [1,2,3] 

a = sum b 

x = sqrt b 

wenn ich das tue ich versuche, eine Unterschrift von vielen Sorten enthalten, Derzeit sieht meine Funktion wie folgt aus:

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

ich das Problem nicht verstehen, wenn ich es zu laufen versuchen:

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

Antwort

9

Ein paar Dinge zu justieren:

0) mod für Ihre Funktion nicht ein guter Name ist, wie es der Name der Modulo-Funktion aus der Standardbibliothek ist. Ich werde es stattdessen norm nennen.

1) Die Art Unterschrift Sie schreiben gemeint ist:

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

[a] ist der Typ einer Liste mit Elementen des Typs a. Die Num a vor der => ist kein Typ, sondern eine Einschränkung, die angibt, dass a ein Zahlentyp sein muss (oder genauer gesagt, es muss eine Instanz der Num Klasse sein). [Num a] => führt zu dem Fehler, den Sie gesehen haben, da der Typüberprüfer bei den eckigen Klammern den Versuch unternimmt, einen Listentyp anstelle einer Einschränkung zu verwenden.

Nach dem Num a Problem haben Sie den Ergebnistyp aus der Signatur weggelassen. Die korrigierte Signatur gibt an, dass Ihre Funktion eine Liste von Zahlen akzeptiert und eine Zahl zurückgibt.

2) Die Num a Einschränkung ist zu schwach für das, was Sie versuchen zu tun. Um sqrt zu verwenden, müssen Sie nicht nur einen Nummerntyp haben, aber eine, die (zu dieser Antwort vgl leftaroundabout Kommentar) eine Instanz von Floating ist:

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

Daher sollten Sie Ihre Unterschrift

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

3) [x] ist eine Liste mit einem einzelnen Element, x. Wenn Ihr Argument bereits eine Liste ist, wie es die Typensignatur sagt, brauchen Sie es nicht in eckige Klammern zu setzen. Ihre Funktion, dann wird:

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

Oder mehr ordentlich, ohne den zweiten where -Block:

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

FTR: trotz des Namens, 'Floating' ist nicht wirklich„die Klasse von Gleitkommazahlen“, das wäre' RealFloat' (oder sogar ['IEEE'] (http://hackage.haskell.org/package/ieee754-0.7.9/docs/Numeric-IEE.html#t:IEEE)). Es ist eher einfach die Klasse von _Number-Typen, mit denen Sie einen Kalkül mit _ erstellen können, was auch Dinge wie exakte reelle Arithmetik erlaubt. – leftaroundabout

+0

@leftaroundabout Vielen Dank für die Hervorhebung; ungenaue Aussage entfernt. – duplode

0

Die kurze Antwort ist, dass [Num a] keine Einschränkung ist. Sie müssen (Num a) oder nur Num a schreiben.

Von Haskell 2010 Language Report

4.1.3 Syntax der Klasse Assertions und Contexts

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

Eine Klasse Behauptung hat Form qtyclstyvar und zeigt die Zugehörigkeit des Typs tyvar in der Klasse Qtcls. Eine Klassenkennung beginnt mit einem Großbuchstaben. Ein Kontext besteht aus null oder mehr Klasse Assertions und hat die allgemeine Form (C1 u1, ..., Cn un) wo C1, ..., Cn sind Klassenkennungen, und jeder der u1, ..., un ist entweder eine Typvariable oder die Anwendung von Typvariable auf einen oder mehrere Typen. Die äußeren Klammern können weggelassen werden, wenn n = 1. In der Regel verwenden wir cx einen Kontext zu bezeichnen, und wir schreiben cx => t den Typ t durch den Kontext cx beschränkt anzuzeigen. Der Kontext cx darf nur Typvariablen enthalten, auf die in t verwiesen wird. Aus praktischen Gründen schreiben wir cx => t, auch wenn der Kontext cx leer ist, obwohl in diesem Fall die konkrete Syntax keine => enthält.

4

Wie Sie wissen, Werte können nach ihrem Typ klassifiziert werden. "foo" hat [Char] zu geben, Just 'c' hat Maybe Char Typ usw.

Auf ähnliche Weise können Typen durch ihre Art klassifiziert werden. Alle konkreten Typen, für die Sie einen Wert angeben können, haben die Art *. Sie können sehen, das die :k Befehl in GHCi mit:

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

Typkonstruktoren auch Arten haben. Sie sind im Wesentlichen typisierte Funktionen, so dass ihre Arten regulären Funktionen ähneln.

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

Aber was ist Num a? Es ist kein Typ, also hat es keine Art *. Es ist kein Typkonstruktor, also hat es keine Pfeilart. Es ist etwas Neues, also wurde eine neue Art geschaffen, um es zu beschreiben.

> :k Num Int 
Num Int :: Constraint 

Und Num selbst ist eine Constraint -wertigen Funktion: es einen Wert von Art * nimmt und ein Constraint:

> :k Num 
Num :: * -> Constraint 

Ein Ding mit Art Constraint wird verwendet, um die typeclass, dass eine bestimmte angeben Typ muss eine Instanz von sein. Dies ist der Wert, der in einer Typsignatur vor => auftreten kann. Es ist auch das „Argument“ der instance „Funktion“:

instance Num Int where 
    ...