2012-04-11 17 views
4

Ich versuche, eine einfache min-Funktion zu implementieren, die zwei Parameter akzeptiert & True zurückgibt, wenn die erste vor dem zweiten in sortierter Reihenfolge, ansonsten False erscheinen muss:Haskell und Ord

min :: a -> a -> Bool 
min a b = if a < b then True else False 

ich:

No instance for (Ord a) 
arising from a use of `<' 
+11

wenn foo dann True else False kann immer umgeschrieben werden als einfach foo – Sarah

+0

Danke dafür! –

+2

Und das nächste Mal, wenn Sie Zweifel haben, können Sie einfach die Typ-Annotation im oberen Bereich weglassen und den Compiler in vielen Fällen fragen. Also: t min gibt mir den korrekten Typ mit der Ord-Einschränkung, wenn ich ghci darüber befrage. – Sarah

Antwort

7

Sie benötigen eine Typeinschränkung für < zu arbeiten:

min :: Ord a => a -> a -> Bool 
--  ^^^^^ 
+0

Es wäre hilfreich, ihnen zu sagen, warum - was eine Art Einschränkung ist. – amindfv

+0

@amindfv: dave4420 hat das schon gemacht und ich habe seine Antwort hochgestuft. –

25

Wenn Sie look at the documentation, sehen Sie, dass der Typ für (<) gegeben als

(<) :: a -> a -> Bool 

Dies ist irreführend!

Die Typdeklaration erscheint in einer typeclass Definition:

class Eq a => Ord a where ... 

So ist die volle Art ist

(<) :: Ord a => a -> a -> Bool 

Übrigens, wenn Sie GHCI fragen, was (<) ‚s-Typ ist, wird es es richtig .

Prelude> :t (<) 
(<) :: (Ord a) => a -> a -> Bool 

Beachten Sie auch, gibt es bereits eine Funktion min, in der gleichen typeclass genannt.

min :: Ord a => a -> a -> a 

So können Sie Ihre Funktion nicht aufrufen min, wenn Sie das Original min verstecken. (Ich werde nicht zeigen, wie. Einen anderen Namen stattdessen für Ihre Funktion verwenden.)


Schließlich haben Sie jetzt

min :: Ord a => a -> a -> Bool 
min a b = if a < b then True else False 

Als Sarah merkt, if blah then True else False ist die gleiche wie blah , so dass Sie auf die klareren

min :: Ord a => a -> a -> Bool 
min a b = a < b 

Jetzt Betreiber in Haskell sind nur Funktionen mit lustigen Namen vereinfachen --- dies ist das gleiche wie

min :: Ord a => a -> a -> Bool 
min a b = (<) a b 

Wir können dies weiter vereinfachen:

min :: Ord a => a -> a -> Bool 
min = (<) 

So Ihre min ist nur ein anderer Name für (<). Warum nicht einfach das Original < anstelle Ihrer min verwenden?

+0

@ gonzoc0ding: Dave ist völlig richtig (+1 übrigens) –

+2

+1 nette Schritt-für-Schritt-Erklärung von 'min a b = wenn a nimi

8

Es gibt bereits zwei Antworten auf diese, aber ich denke, es ist ein wichtiger Punkt fehlt:

Der Grund, die Sie (Ord a) => in Ihrer Art Unterschrift brauchen, ist, dass Sie die Typen beschränken müssen, die erlaubt sind „in "Ihre Funktion.

Wenn ich eine Funktion function :: a -> a definiere, sage ich, dass meine Funktion Daten von beliebigen Typ nimmt und einen Wert des gleichen Typs zurückgibt.

Ein gutes Beispiel hierfür ist head :: [a] -> a - gegeben eine Liste von jeder Typ, Kopf wird das erste Argument der Liste zurückgeben. Das liegt daran, dass der Kopf die Daten selbst nicht wirklich "anfasst", so dass es überhaupt keine Rolle spielt, was es ist.

Allerdings ist Ihre Situation so nicht: denken wir uns einen Datentyp Länder haben:

data Countries = USA | Nigeria | China | Canada -- yes, I know there are a few missing 

Es macht keinen Sinn min USA Canada oder USA < Canada zu sagen.

Deshalb müssen Sie Ihre Funktionen auf Typen beschränken, die auf diese Weise verglichen werden können: Typen, die Instanzen der Klassenklasse Ord (Bedeutung geordnet) haben. Die Art und Weise, wie Sie sie einschränken, lautet (Ord a) => vor Ihrer Typ-Signatur.