[Haskell-ELTE] Mivel etessem a függvényemet? :)
Dévai Gergely
deva at inf.elte.hu
2010. Május. 19., Sze, 14:25:09 CEST
Sziasztok!
Adott egy tetszőleges adattípus, például ez:
data Foo = Bar | Baz Foo Foo
A feladat az
isConstant :: (Foo -> Foo) -> Bool
függvény megírása, amelynek el kell döntenie, hogy az argumentuma
konstans függvény-e.
Nem általában szeretném ezt megoldani, hanem csak speciális tulajdonságú
függvények esetén kell jól működnie.
Nevezzünk egy függvényt "konstruktor-szerű" függvénynek, ha nem cincálja
szét az argumentumát, legfeljebb beleteszi az eredménybe, mint egy
építőkockát.
Példák konstruktor-szerű függvényekre: id, \x -> Bar, \x -> Baz x Bar
Példa nem konstruktor-szerű függvényre:
\x -> case x of
Bar -> Baz Bar Bar
Baz y _ -> y
Sajnos nem tudom, hogy "igazából" hogy hívják ezt a függvény-osztályt,
de szeretném tudni. :)
A feladat tehát az, hogy konstruktor-szerű függvényekre jól működjön az
isConstant.
1. megoldás:
Hozzáveszünk egy Dummy alternatívát az adattípushoz, megetetjük a
függvényt egy Dummy-val, majd megnézzük az eredményt, hogy belekerült-e
a Dummy.
data Foo
= Bar | Baz Foo Foo | Dummy
isConstant :: (Foo -> Foo) -> Bool
isConstant f = dummyLess $ f Dummy where
dummyLess Bar = True
dummyLess (Baz f1 f2) = dummyLess f1 && dummyLess f2
dummyLess Dummy = False
Ez a megoldás azért nem tetszik, mert hozzá kellett nyúlni az
adattípushoz, ráadásul biztosítani kell, hogy más célra a Dummy-t
véletlenül se használják.
2. megoldás:
Az adattípus érintetlenül marad, a függvényt egy kivétellel etetjük meg,
majd bejárjuk az eredményt és elkapjuk az esetlegesen fellépő kivételt.
import Control.Exception
import System.IO.Unsafe
data Foo
= Bar | Baz Foo Foo
instance Exception () where
toException () = SomeException ()
fromException _ = Just ()
walk :: Foo -> IO Int
walk Bar = return 1
walk (Baz f1 f2) = do
x <- walk f1
y <- walk f2
return $ x+y
isConstant :: (Foo -> Foo) -> Bool
isConstant f = unsafePerformIO $ do
x <- try $ walk $ f $ throw () :: IO (Either () Int)
case x of
Right _ -> return True
Left _ -> return False
Ez a megoldás azért nem tetszik, mert unsafePerformIO-zik. Épp ezért a
helyességéről sem vagyok meggyőződve.
Tudtok-e jobb megoldást?
Köszi,
Gergő
More information about the Haskell
mailing list