Art*_*ung 4 haskell functional-programming polyvariadic
我正在尝试在Haskell中创建一个polyvariadic函数,我用这个答案来创建一个基本函数.这是函数的代码:
class SumRes r where
sumOf :: Integer -> r
instance SumRes Integer where
sumOf = id
instance (Integral a, SumRes r) => SumRes (a -> r) where
sumOf x = sumOf . (x +) . toInteger
Run Code Online (Sandbox Code Playgroud)
但问题是:在没有任何参数的情况下调用函数时,它不起作用.
Couldn't match expected type 'Integer' with actual type 'Integer -> r0'
Probable cause: 'sumOf' is applied to too few arguments
Run Code Online (Sandbox Code Playgroud)
例如,我希望能够编写sumOf :: Integer并返回此函数0.
我该怎么做?
最简单的版本仅适用于Integer结果.
这可以解决你已经编写的内容,利用0了添加标识这一事实.
class SumRes r where
sumOf' :: Integer -> r
instance SumRes Integer where
sumOf' = toInteger
instance (Integral b, SumRes r) => SumRes (b -> r) where
sumOf' a b = sumOf' $! a + toInteger b
sumOf :: SumRes r => r
sumOf = sumOf' 0
Run Code Online (Sandbox Code Playgroud)
这两个实例,Integer并且b -> r本质上不重叠.
要获得更一般的结果类型,您需要一种稍微不同的方法,因为如果Integer由类型变量替换,上面描述的两个实例会混在一起.你可以用MultiParamTypeClasses和做TypeFamilies.
{-# LANGUAGE ScopedTypeVariables, AllowAmbiguousTypes, DataKinds,
KindSignatures, TypeApplications, MultiParamTypeClasses,
TypeFamilies, FlexibleInstances #-}
module SumRes2 where
data Nat = Z | S Nat
class SumRes (c :: Nat) r where
sumOf' :: Integer -> r
type family CountArgs a :: Nat where
CountArgs (_ -> r) = 'S (CountArgs r)
CountArgs _ = 'Z
instance Num r => SumRes 'Z r where
sumOf' = fromInteger
instance (Integral b, SumRes n r) => SumRes ('S n) (b -> r) where
sumOf' a b = sumOf' @n (a + toInteger b)
sumOf :: forall r n. (SumRes n r, CountArgs r ~ n) => r
sumOf = sumOf' @n 0
Run Code Online (Sandbox Code Playgroud)
唯一的限制是,如果您有Integral一个函数类型的实例,则不能用它sumOf来生成它.但这不应该是一个问题.我已经使用TypeApplications并AllowAmbiguousTypes为简洁,但你肯定可以使用代理服务器通过或Tagged代替.