haskell - 在 Haskell 中使用类型类作为可变参数模式

标签 haskell recursion typeclass

假设我在 Haskell 中有一个约定,我定义了一系列如下函数:


data Node = MkNode

s0 :: Node -> s -> Node
s0 a _ = a

s1 :: (s -> a) -> (a -> Node) -> s -> Node
s1 a b c = b (a c)

s2 :: (s -> a) -> (s -> b) -> (a -> b -> Node) -> s -> Node
s2 a b c d = c (a d) (b d)

s3 :: (s -> a) -> (s -> b) -> (s -> c) -> (a -> b -> c -> Node) -> s -> Node
s3 a b c d e = d (a e) (b e) (c e)

如果可能的话,我希望定义一个函数 sn ,它接受可变数量的参数,并且始终采用这种模式。我在使用类型类之前见过这种事情,但我不太清楚在这种情况下如何做。例如,我可以想象:

class NAble elt where
    sn :: elt -> state -> Node

instance NAble Node where
    sn elt _ = elt

但后来我陷入困境。我不确定递归定义是什么。也许是这样的:

instance (NAble b) => NAble (a -> b) where
    sn eltMaker state = ss (eltMaker state) state

但这显然不太正确。不确定这是否可能,但如果可以的话那就太酷了。当然,如果这有助于正确的话,参数的顺序可以改变,但是让它发挥作用真是太好了。任何帮助将不胜感激!

最佳答案

如果您以稍微不同的顺序放置参数 - 使用 s参数首先出现,而 Node - 其次构造函数——它变得容易多了。然后类型系列将立即修复您:

{-# LANGUAGE TypeFamilies #-}

data Node = MkNode

class NAble t where
    type Ret t s
    sn :: s -> t -> Ret t s

instance NAble Node where
    type Ret Node s = Node
    sn s mkNode = mkNode

instance NAble t => NAble (a -> t) where
    type Ret (a -> t) s = (s -> a) -> Ret t s
    sn s mkNode fa = sn s (mkNode (fa s))

但让我也推荐一个替代方案。查看标准库使用的模式:

pure   :: Applicative f => (               t)                      -> f t
fmap   :: Applicative f => (a ->           t) -> f a               -> f t
liftA2 :: Applicative f => (a -> b ->      t) -> f a -> f b        -> f t
liftA3 :: Applicative f => (a -> b -> c -> t) -> f a -> f b -> f c -> f t

服用f~(->) st~Node ,我们得到:

pure   :: (               Node)                                     -> s -> Node
fmap   :: (a ->           Node) -> (s -> a)                         -> s -> Node
liftA2 :: (a -> b ->      Node) -> (s -> a) -> (s -> b)             -> s -> Node
liftA3 :: (a -> b -> c -> Node) -> (s -> a) -> (s -> b) -> (s -> c) -> s -> Node

如果使用标准库的人需要liftA4怎么办?或更高?通常他们会切换到 (<*>) 链使用:

(<*>) :: (s -> a -> Node) -> (s -> a) -> s -> Node
(f <*> g) s = f s (g s)

{-# MAKE_THE_PROGRAMMER_INLINE liftAn #-}
liftAn mkNode f1 f2 ... fn = pure mkNode
    <*> f1
    <*> f2
    ...
    <*> fn

关于haskell - 在 Haskell 中使用类型类作为可变参数模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61440490/

相关文章:

Haskell - 将函数映射到玫瑰树上

Haskell Prelude 带有隐藏,如何撤消?

sorting - 没有累加器可以写这个吗?

haskell - MultiParamTypeClasses - 为什么这个类型变量不明确?

haskell - 显式导入实例

haskell - 数据类型是一对函数?

haskell - 将 base64-bytestring 与惰性 ByteString 结合使用

java - 在树数据结构中添加节点时递归

python - 为什么这个抛出错误的递归 Python 函数在最后几次调用中来回跳转?

Haskell 继承类型类