Spezialisierung in Typklassen mit ghc
-
11-09-2019 - |
Frage
Wie kann ich das genOut / String Feuer machen?
module IOStream where
import System.IO
import System.IO.Unsafe
class Out a where
out :: a → String
instance Show a ⇒ Out a where
out = show
outString :: String → String
outString = id
{-# RULES "genOut/String" out = outString #-}
infixl 9 <<, ≪
(≪), (<<) :: Out a ⇒ IO Handle → a → IO Handle
(<<)= (≪)
h ≪ a = do
s ← h
hPutStr s $ out a
return s
cout, cin, cerr :: IO Handle
cout = return stdout
cin = return stdin
cerr = return stderr
endl :: String
endl = "\n"
--infixr 9 ∘ °
(∘) = (.)
(°) = flip (∘)
module Main where
import System.IO
import IOStream
foreign import ccall "pi.h f_" f_ :: IO Double
main :: IO Int
main = do
--putStrLn . show =<< f_
-- ((≪ endl) . (cout ≪)) =<< f_
(cout ≪) ° (≪ endl) =<< f_
return 0
Übersetzen und Link:
cetin@unique:~/lab/c/linking/demo$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 6.10.2
cetin@unique:~/lab/c/linking/demo$ ghc -fglasgow-exts -O2 -ddump-simpl-stats -XUndecidableInstances -O2 iostream.hs main.hs pi_v2.o -o hsex2
==================== FloatOut stats: ====================
0 Lets floated to top level; 1 Lets floated elsewhere; from 3 Lambda groups
==================== FloatOut stats: ====================
0 Lets floated to top level; 0 Lets floated elsewhere; from 5 Lambda groups
==================== Grand total simplifier statistics ====================
Total ticks: 184
40 PreInlineUnconditionally
45 PostInlineUnconditionally
24 UnfoldingDone
8 LetFloatFromLet
4 EtaReduction
57 BetaReduction
6 KnownBranch
11 SimplifierDone
==================== FloatOut stats: ====================
0 Lets floated to top level; 0 Lets floated elsewhere; from 1 Lambda groups
==================== FloatOut stats: ====================
3 Lets floated to top level; 0 Lets floated elsewhere; from 1 Lambda groups
==================== Grand total simplifier statistics ====================
Total ticks: 218
42 PreInlineUnconditionally
57 PostInlineUnconditionally
33 UnfoldingDone
9 LetFloatFromLet
1 EtaReduction
66 BetaReduction
10 KnownBranch
12 SimplifierDone
Ergebnis:
cetin@unique:~/lab/c/linking/demo$ ./hsex2
3.141592653589793"\n"cetin@unique:~/lab/c/linking/demo$
Erwartet:
cetin@unique:~/lab/c/linking/demo$ ./hsex2
3.141592653589793
cetin@unique:~/lab/c/linking/demo$
Wie kann ich diese Regel Feuer machen?
Lösung
Es sieht aus wie Sie überlappende Instanzen , wie Sie wollen eine instance Out String
haben, die als instance Show a => Out a
unterscheiden, die es überlappt.
{-# LANGUAGE FlexibleInstances, TypeSynonymInstances #-}
{-# LANGUAGE OverlappingInstances, UndecidableInstances #-}
class Out a where out :: a -> String
instance Out String where out = id
instance (Show a) => Out a where out = show
Die allgemeine Empfehlung ist die Verwendung von überlappenden Instanzen und unentscheidbar Instanzen zu vermeiden, es sei denn, wirklich erforderlich, da die Änderungen Typprüfung, dass sie machen, sind nicht tragbar und kann andere Probleme verursachen.
Bearbeiten
Die Umsetzung weisen, denken Sie an Wörterbuch für jede Instanz einer Klasse. <<
wird das Wörterbuch für die Instanz von Out
gegeben werden, das erwartet wird, als versteckter Parameter zu verwenden. Da out
von dort nachgeschlagen wird, gibt es keinen Platz für Ihre RULE
abzufeuern. Wenn out
nicht in einer typeclass waren, und wurde aus einer nicht-polymorphe Funktion aufgerufen wird, dann würde ich die RULE
erwarten übereinstimmen, aber wie es ist, ist es nicht verwunderlich, dass es nicht funktioniert.
RULE
/ SPECIALIZE
sollen Optimierungen nur sein, und Ihr Code sollte nicht Verhalten ändern, wenn sie es tun oder nicht feuern.
Es dauerte eine Weile zu erkennen, was Sie taten ... Sie erkennen, dass Haskell nicht C ++, nicht wahr? Die Art und Weise, in dem Polymorphismus verwendet wird, ist ganz anders.