【问题标题】:Optimisation based on function result type基于函数结果类型的优化
【发布时间】:2017-02-18 08:17:30
【问题描述】:

下面是一个可能很愚蠢的例子,但我认为解决这个问题将解决我遇到的另一个问题,详细 in this question

我想用这个签名写一个函数:

myread :: (Read a) => String -> a

这样,myread = read,除非a ~ Int,在这种情况下myread _ = 0

显然这个函数本身很傻,但重点是我想根据返回类型进行优化。

重写规则,或者这里什么都可以。对于我的实际问题,如果解决方案是重写规则,那么是否存在不触发的情况并不重要,但我希望答案至少给出一个示例。

【问题讨论】:

  • 您似乎已经有了正确的工具——a 上的类约束。当然,您无法控制 Read Int 实例,但在您的实际用例中,您似乎确实控制了类的定义和实例。或者我误解了你所说的“优化”是什么意思? (旁白:我认为另一个答案中的解决方案不起作用,因为x :: H a => T a 不是指“上下文H a 中类型为T a 的x”而是“类型为'H a => T a 的x”,即该规则将应用于 (Read a => F a) -> X 而不是 Read a => F a -> X )
  • 我无法控制Read 类,并且当Int 已经存在时,我无法为Int 创建自己的Read 实例。可能我误会你了。

标签: haskell optimization ghc


【解决方案1】:

您可以直接使用重写规则执行此操作,以(也许)显而易见的方式,如果您记得规则的左侧在 表达式 上下文中,不是 em> 在模式上下文中。特别是左侧的类型应用程序是完全有效的。

{-# LANGUAGE TypeApplications #-} 

module A where 

{-# INLINE [1] myread  #-}
{-# RULES "myread" forall s . myread @Int s = 0 #-}

myread :: Read a => String -> a 
myread = read 

即使没有类型应用程序,以下内容也是完全有效的(但可能不是一般情况下,例如,如果输出类型是 f a 并且您只想“优化”f,则不能有 .. = (result :: [ _ ]) ):

{-# RULES "myread" forall s . myread s = (0 :: Int) #-}

作为一个例子使用

module B where 

import A 

fun :: String -> String -> (Int, Bool) 
fun x y = (myread x, myread y) 

规则触发的证据当然是查看核心(省略不相关的部分):

fun4 :: Int
fun4 = I# 0#

fun :: String -> String -> (Int, Bool)
fun =
  \ _ (w1 :: String) ->
    (fun4,
     case readEither6 (run fun3 w1) of _ {
       [] -> fun2;
       : x ds ->
         case ds of _ {
           [] -> x;
           : ipv ipv1 -> fun1
         }
     })

请注意,这实际上是一个评论,而不是一个答案,因为我不确定目标到底是什么,但代码不适合评论。

【讨论】:

    【解决方案2】:

    如何定义一个具有不确定实例的新类?

    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE UndecidableInstances #-}
    
    class MyRead a where
      myread :: String -> a
    
    instance {-# OVERLAPPABLE #-} Read a => MyRead a where
      myread = read
    
    instance MyRead Int where
      myread = const 0
    
    main = do
      print $ (myread "True" :: Bool) -- True
      print $ (myread "\"string\"" :: String) -- "string"
      print $ (myread "12" :: Int) -- 0
    

    【讨论】:

    • 在这种情况下,MyRead 具有签名myread :: MyRead a => String -> a。如问题中所述,需要签名为myread :: Read a => String -> a(否则无法解决相关问题中的问题)。
    猜你喜欢
    • 2017-05-12
    • 1970-01-01
    • 1970-01-01
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    相关资源
    最近更新 更多