Universeller Transformator in Haskell
Logischerweise ist es möglich, universelle Transformationsfunktionen zu definieren, die von jedem Typ in jeden Typ transformiert werden können.
Der mögliche Weg ist:
{-#LANGUAGE MultiParamTypeClasses #-}
{-#LANGUAGE FlexibleInstances #-}
class FromTo a b where
fromTo:: a->b
instance FromTo a a where fromTo = id
instance FromTo Int Double where fromTo = fromIntegral
instance FromTo Int Float where fromTo = fromIntegral
instance FromTo Integer Double where fromTo = fromIntegral
instance FromTo Integer Float where fromTo = fromIntegral
instance FromTo Double Int where fromTo = round
instance FromTo Double Integer where fromTo = round
instance FromTo Float Int where fromTo = round
instance FromTo Float Integer where fromTo = round
-- e.t.c.
Nun, es funktioniert, es ist erweiterbar. Aber es ist sehr sperrig, weil ich jeden Fall auflisten muss, den ich verwenden möchte.
Gibt es dafür gute Lösungen?
Die ordentliche Lösung könnte so aussehen, wenn sie richtig wäre(aber es ist nicht):
{-#LANGUAGE MultiParamTypeClasses #-}
{-#LANGUAGE FlexibleInstances #-}
{-#LANGUAGE InstanceSigs #-}
class FromTo a b where
fromTo:: a->b
instance (Integral a, Num b) => FromTo a b where
fromTo::a->b
fromTo x = (fromIntegral x)
{---Commented, because addition breaks program.-------------------------------
instance (RealFrac a, Integral b) => FromTo a b where
fromTo::a->b
fromTo x = (round x)
-}
Vielleicht wäre es möglich, wenn es eine Erweiterung für Typensätze gäbe (Haskell-ähnlicher Pseudocode):
{-#LANGUAGE MultiParamTypeClasses #-}
{-#LANGUAGE FlexibleInstances #-}
{-#LANGUAGE InstanceSigs #-}
{-#LANGUAGE TypeSets #-}
class FromTo a b where
fromTo:: a->b
instance setfrom (Integral a, Num b). (Integral a, Num b) => FromTo a b where
fromTo::a->b
fromTo x = (fromIntegral x)
instance setfrom (RealFrac a, Integral b). (RealFrac a, Integral b) => FromTo a b where
fromTo::a->b
fromTo x = (round x)
setfrom C1 a.
Hier sollte eine Menge von Typen definiert werden, die Instanzinformationen von verwendenC1
Klasse. Der Compiler sollte prüfen, ob sich Instanzen überschneiden. Die andere mögliche Konstruktion dieser Erweiterung istset (T1,T2,...,TN) a.
Damit kann lediglich der Typensatz definiert werden.
UPD 1
Die 1. Lösung könnte auf diese Weise verbessert werden (aber es istfalsch Weg):
{-#LANGUAGE MultiParamTypeClasses #-}
{-#LANGUAGE FlexibleInstances #-}
class FromTo a b where
fromTo:: a->b
instance FromTo a a where fromTo = id
instance Num b => FromTo Int b where
fromTo x = fromIntegral x
instance Num b => FromTo Integer b where
fromTo x = fromIntegral x
instance Integral b => FromTo Float b where
fromTo x = round x
instance Integral b => FromTo Double b where
fromTo x = round x
Aber es ist immer noch nicht gut und zusätzlichgibt Überlappungen beim Aufrufen im interaktiven Modus:
*Main> fromTo (10::Double) ::Double
<interactive>:108:1:
Overlapping instances for FromTo Double Double
arising from a use of `fromTo'
Matching instances:
instance FromTo a a -- Defined at 4.hs:8:10
instance Integral b => FromTo Double b -- Defined at 4.hs:19:10
In the expression: fromTo (10 :: Double) :: Double
In an equation for `it': it = fromTo (10 :: Double) :: Double