Har lite problem med klasser i Haskell. I <b>x <*> (Vec1 y) = (Vec1 (x*y))</b> måste x och y tillhöra samma typ, och denna typ måste implementera klassen Num. Men enligt dina typdeklarationer räcker det om x och y har olika typer som var för sig implementerar klassen Num. (Skall erkänna att jag är litet osäker...) Detta funkar i Hugs: Perfekt!Klasser i Haskell?
Jag skulle vilja ha en generell klass "vektor", för allmäna vektorrum. (Detta är för en enkel ODE-applikation.)
Då tänker jag att följande är rimligt:
class Vector a where
(<*>) :: Num b => b -> a -> a
(<+>) :: a -> a -> a
Alltså en instans a av en vektor ska kunna bli multiplicerad med en skalär och ska kunna bli adderad med en annan vektor.
Det tycks vara ok, sen försöker jag med:
data Vec1 a = Vec1 {u::a}
instance (Num a) => Vector (Vec1 a) where
(Vec1 x) <+> (Vec1 y) = (Vec1 x)
x <*> (Vec1 y) = (Vec1 (x*y))
Men <*> fullkomligt vägrar den att acceptera:
ERROR "RungeKutta.hs":17 - Inferred type is not general enough
*** Expression : (<*>)
*** Expected type : (Vector (Vec1 a), Num b) => b -> Vec1 a -> Vec1 a
*** Inferred type : (Vector (Vec1 a), Num a) => a -> Vec1 a -> Vec1 a
Antar att det är något enkelt problem, någon som har en förklaring?Sv: Klasser i Haskell?
Undrar om du inte måste ange även skalärtypen i Vector-klassen:
-- Anger att a är en vektor över b
class Num b => Vector a b where
(<*>) :: b -> a -> a
(<+>) :: a -> a -> a
data Vec1 a = Vec1 {u::a}
instance (Num a) => Vector (Vec1 a) a where
(Vec1 x) <+> (Vec1 y) = (Vec1 x)
x <*> (Vec1 y) = (Vec1 (x*y))
Skall installera Hugs och testa...Sv:Klasser i Haskell?
class Vector v where
(<+>) :: Num a => v a -> v a -> v a
(<*>) :: Num a => a -> v a -> v a
newtype Num a => Vec a = Vec a
deriving Show
instance Vector Vec where
(Vec x) <+> (Vec y) = Vec (x + y)
c <*> (Vec x) = Vec (c * x)Sv: Klasser i Haskell?
Efter en hel del krånglande har jag nu fått ordning på hela grejen. En komplett utbyggbar RungeKutta-lösare av andra ordningen för godtyckliga vektorrum på 75 rader inklusive tomrader.
import IO
class Vector v where
(<+>) :: Num a => v a -> v a -> v a
(<*>) :: Num a => a -> v a -> v a
newtype Num a => Scalar a = Scalar a
instance Num a => Show (Scalar a) where
show (Scalar x) = (show x)
instance Vector Scalar where
(Scalar x) <+> (Scalar y) = Scalar (x + y)
c <*> (Scalar x) = Scalar (c * x)
data Num a => Vec2 a = Vec2 a a
instance Num a => Show (Vec2 a) where
show (Vec2 x y) = (show x) ++ " " ++ (show y)
instance Vector Vec2 where
(Vec2 x1 y1) <+> (Vec2 x2 y2) = Vec2 (x1 + x2) (y1 + y2)
c <*> (Vec2 x y) = Vec2 (c * x) (c * y)
f :: (Num a, Num b) => b -> Scalar a -> Scalar a
f t x = x
g :: Num a => a -> Vec2 a -> Vec2 a
g t (Vec2 u v) = Vec2 (u + v) (v - u)
runge_kutta :: (Ord a, Num a, Vector b) => (a -> b a -> b a) ->
b a -> a -> a -> a -> [(b a, a)]
runge_kutta f y0 t0 tmax tstep
| t0>tmax = []
| otherwise = (y1,t1) : (runge_kutta f y1 t1 tmax tstep)
where
y1 = runge_kutta_aux f y0 t0 tmax tstep
t1 = t0 + tstep
runge_kutta_aux :: (Num a, Vector b) => (a -> b a -> b a) ->
b a -> a -> a -> a -> b a
runge_kutta_aux f y0 t0 tmax tstep =
y0 <+> k2
where
k1 = tstep <*> (f t0 y0)
k2 = tstep <*> (f (t0+tstep) (y0 <+> k1))
out_to_matlab result = "y = [" ++ unlines (map (++ ";") (map show y)) ++ "]\n"
where
(y,t) = unzip(result)
calc_final_result =
out_to_matlab final_result
where
final_result = runge_kutta f (Scalar 1) 0 5 0.001
-- final_result = runge_kutta g (Vec2 0.1 0.5) 0 5 0.001
main = do
handle <- openFile "output.m" WriteMode
hPutStr handle calc_final_result
Nu ska vi bara se om vi kan få ordning på en matris också.