2017-11-17 1 views
7

Ich habe eine Funktion, die den Preis eines Produktes gibt, sieht es derzeit wieTyp "Name" = Int - ist es wert zu deklarieren?

priceOfProduct:: Int -> Int -> Int 

Ist es erklärt wert

type Price = Int 

so dass die Funktion

priceOfProduct :: Int -> Int -> Price ? 

wird dachte ich Ich mache dann Tupel von Ints, die vielleicht besser aussehen würden, wenn sie ihre eigene Datenstruktur hätten.

priceVsTaxed -> Price -> Int -> (Price, Price) 

Ist das nützlich? Ist das notwendig?

Ist das ein guter Haskell-Stil?

Wird eine Datenstruktur deklariert, die eher dem Umbenennen einer vorhandenen guten Datenstruktur ähnelt?

+1

'Int -> Int -> Preis 'ist nicht so hilfreich, weil der Name der Funktion bereits stark bedeutet, dass ein Preis zurückgegeben wird. 'type Quantity = Int' und' type UnitPrice = Int' würden jedoch die viel hilfreichere 'priceOfProduct :: Quantity -> UnitPrice -> Price erlauben. – chepner

+0

Es ist auch eine einfache Möglichkeit, den Typ zu ändern, wenn Sie nicht sicher sind, ob es am Ende passt. –

Antwort

11

Es ist nicht immer Wert, zusätzliche Typen zu definieren, aber vermeiden Sie unbedingt Int -> ... -> Int Signaturen. Diese machen es sehr schwer zu verstehen, wie eine Funktion verwendet werden soll.

In der Tat würde ich sagen, dass Sie wahrscheinlich nicht nur das Ergebnis, sondern insbesondere auch die Argumente umbenennen sollten. Dann, wenn jemand will, um Ihre Funktion nutzen, können sie nur lassen Sie den Compiler die Argumente erklären:

foo :: Price 
foo = priceOfProduct _ _ + priceOfProduct _ _ 

einen Compiler geben (GHC> = 7,10) Meldung wie

Foo.hs:Y:X: error: 
    • Found hole: _ :: PriceOfProductFirstArgument 
    • In the first argument of ‘priceOfProduct’, namely ‘_’ 
     In the expression: priceOfProduct _ _ 
     In an equation for ‘foo’: main = foo = priceOfProduct _ _ + priceOfProduct _ _ 

Sie jedoch beachten sollte wenn Sie die Art Unterschied machen wollen steifer nicht: ein einfaches type def kann man nie aus speichern, die Argumente in falscher Reihenfolge setzen, vielleicht würden Sie besser machen es

newtype Price = Price {priceInEuroCents :: Int} 

Das vermeidet auch Mehrdeutigkeit, in welcher Währung/Menge der Preis angegeben ist.

+1

Kleiner Zusatz zum letzten 'newtype':' newtype Preis u = Preis {getPrice :: Int} 'mit' data Euro', 'dataUSollar', ... ermöglicht es,' Price'-Funktionen mit verschiedenen Währungen wiederzuverwenden. – Zeta

+1

@ Zeta, das ist wahrscheinlich das Richtige für reale Finanzanwendungen (weil Währungswechsel keine Isomorphie ist), aber ich mag diesen Ansatz im Allgemeinen nicht für Mengen mit Einheiten. Ein solcher Datentyp sollte IMO über den allgemeinen physikalischen Begriff dieser Menge abstrahieren, ohne auf ein konkretes Einheitensystem Bezug zu nehmen. – leftaroundabout

Verwandte Themen