使用ghc的类型类专门化

时间:2022-04-27 16:55:36

How can I make the genOut/String fire?

如何使genOut / String激活?

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?

我怎样才能解决这条规则?

1 个解决方案

#1


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.

看起来你想要重叠实例,因为你想要一个实例Out String,它与实例Show a => Out a不同,后者重叠它。

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

在实现方面,考虑每个类的实例的字典。 < <将给出out的实例的字典,它将被用作隐藏参数。因为从那里向外看,所以你的rule没有空间可以射击。如果out不在类型类中,并且是从非多态函数中调用的,那么我希望rule能够匹配,但是它不会令人惊讶它不起作用。< p>

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

RULE / SPECIALIZE仅用于优化,如果它们执行或不启动,则代码不应更改行为。

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.

我花了一段时间才意识到你在做什么......你确实意识到Haskell不是C ++,对吧?利用多态性的方式是完全不同的。

#1


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.

看起来你想要重叠实例,因为你想要一个实例Out String,它与实例Show a => Out a不同,后者重叠它。

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

在实现方面,考虑每个类的实例的字典。 < <将给出out的实例的字典,它将被用作隐藏参数。因为从那里向外看,所以你的rule没有空间可以射击。如果out不在类型类中,并且是从非多态函数中调用的,那么我希望rule能够匹配,但是它不会令人惊讶它不起作用。< p>

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

RULE / SPECIALIZE仅用于优化,如果它们执行或不启动,则代码不应更改行为。

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.

我花了一段时间才意识到你在做什么......你确实意识到Haskell不是C ++,对吧?利用多态性的方式是完全不同的。