haskell - 在 Haskell 中为可变参数模式使用类型类
问题描述
假设我在 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
-constructing 函数——它会变得容易得多。然后一个类型系列将立即解决您的问题:
{-# 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~(->) s
和t~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
推荐阅读
- python - 灵活地将文件夹中的每个图像文件定义为 ImageTk 对象
- python - 从使用 Airflow KubernetesPodOperator 启动的 Pod 获取上下文
- ios - 如何在渲染回调中交错非交错的 AudioBufferList?
- javascript - 如何使用 Javascript 动态更新运输进度条?
- javascript - 如何使用节点 js 将 PDF 存储在 mysql 数据库中并表达
- r - 将数值向量缩放到指定的平均值、最小值和最大值
- c++ - 类方法不返回值
- postgresql - Rust serde_json::value::RawValue 给出错误“不满足 trait bound ... `r2d2_postgres::postgres::types::FromSql<'_>`”
- python - 例外:带有 Gradio 库的 MissingSchema
- python - 尝试获取 IBM Cloud Object Storage 中的所有存储桶时出现异常