Question

How can I make the genOut/String fire?

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

Compile and 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

Result:

cetin@unique:~/lab/c/linking/demo$ ./hsex2
3.141592653589793"\n"cetin@unique:~/lab/c/linking/demo$ 

Expected:

cetin@unique:~/lab/c/linking/demo$ ./hsex2
3.141592653589793
cetin@unique:~/lab/c/linking/demo$ 

How can I make that rule fire?

Was it helpful?

Solution

It looks like you want overlapping instances, as you want to have an instance Out String which is different than instance Show a => Out a which overlaps it.

{-# 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

The general recommendation is to avoid use of overlapping instances and undecidable instances unless truly necessary, as the changes to typechecking that they make are not portable and can cause other issues.


Edit

Implementation-wise, think of dictionary for each instance of a class. << will be given the dictionary for the instance of Out that it is expected to use as a hidden parameter. Since out is being looked up from there, there's no room for your RULE to fire. If out weren't in a typeclass, and was being called from a non-polymorphic function, then I would expect the RULE to match, but as is, it's not surprising that it doesn't work.

RULE/SPECIALIZE are meant to be optimizations only, and your code should not change behavior if they do or do not fire.

It took me a while to realize what you were doing… you do realize that Haskell is not C++, right? The ways in which polymorphism is utilized is quite different.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top