Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/meteor/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 将单实例类转换为函数_Haskell_Ghc - Fatal编程技术网

Haskell 将单实例类转换为函数

Haskell 将单实例类转换为函数,haskell,ghc,Haskell,Ghc,我写了一些玩具代码来演示我的问题: {-# LANGUAGE DataKinds, PolyKinds, UndecidableInstances, ScopedTypeVariables, FlexibleInstances, TypeFamilies #-} import GHC.TypeLits import Data.Proxy main :: IO ()

我写了一些玩具代码来演示我的问题:

{-# LANGUAGE DataKinds,
             PolyKinds,
             UndecidableInstances,
             ScopedTypeVariables,
             FlexibleInstances,
             TypeFamilies #-}

import GHC.TypeLits
import Data.Proxy

main :: IO ()
main = print $ show $ sumTypeVals (Proxy :: Proxy 4)

class HasVal x where
  val :: Proxy x -> Int

instance (KnownNat nat) => HasVal (nat :: Nat) where
  val = fromIntegral . natVal

type family Div2 (x :: k) :: k
type instance Div2 4 = 2
type instance Div2 2 = 1
type instance Div2 1 = 0
type instance Div2 0 = 0

-- compute sum of all powers of two
class Sum x where
  sumTypeVals :: Proxy x -> Int

instance (HasVal x, Sum (Div2 x)) => Sum x where
  sumTypeVals y | val y == 0 = 0
  sumTypeVals (y::Proxy x) = (val y) + sumTypeVals (Proxy :: Proxy (Div2 x))
上面的代码可以编译。
Sum
的实例适用于任何类型的数字表示,而不仅仅是
TypeLits
。由于
Div2
中的循环,单个实例就足够了,并且比使用第二个实例作为基本情况更加协调,因为:

  • 对于您想要使用的每种数字表示形式,我们都需要一个新的基本情况实例(例如,模式匹配其具体表示形式0)
  • 这些实例编写起来很简单
  • 它们需要
    -XOverlappingInstances
    一个类只有一个实例,涵盖了所有可能的情况,这让人感觉非常像一个函数。下面是我尝试进行的转换(这将替换类/实例):

    当然,问题是使用不同类型的递归调用。GHC-7.8(正确)
    无法推断(HasVal(Div2 x))
    ,这在类/实例设置中不是问题,因为实例上存在递归类约束。虽然编写一个类的单个实例并不过分繁重,但函数似乎是更好的解决方案有几个原因:

  • 为什么要在函数足够时编写方法(如果在这种情况下确实可以)
  • 使用类为以后使用
    -XIncoherentInstances
    并覆盖我的通用实现的人打开了大门编辑:如果在定义类时未使用
    不连贯性
  • 问题:有没有办法将方法
    sumTypeVals
    转换为函数


    对我来说,最明显的修复方法是以某种方式说服GHC,HasVal x=>HasVal(Div2 x)(我非常乐意做出这样的假设)。然而,我不知道有什么方法可以做到这一点。我试着关闭类型族
    Div2
    ,但这似乎对推断没有帮助,尽管我觉得应该这样做。还有其他想法吗?

    您是否在type类中实际使用了
    sumTypeVals
    ?当我在ghci中对其使用
    :t
    时,我得到了“上下文缩减堆栈溢出”。啊,当您实际使用一个具体参数调用它时,我看到它确实起作用,例如
    sumTypeVals(Proxy::Proxy 4)
    。这是一个奇怪的函数@AndrewC我只是想找到一种最简洁的方法来做类型级的算术(比如2的幂和运算),它在这些数字的类型/类型表示上是多态的。例如,我一直在使用Data.Reflection(kind
    *
    ),但我也在考虑GHC.TypeLits(kind
    Nat
    )和Data.Natural?有朝一日,单例可以从普通函数生成sumtypeval。
    sumTypeVals :: (HasVal x) => Proxy x -> Int
    sumTypeVals y | val y == 0 = 0
    sumTypeVals (y::Proxy x) = (val y) + sumTypeVals (Proxy :: Proxy (Div2 x))