haskell——设置定点库?

haskell——设置定点库?,haskell,fixpoint-combinators,fixed-point-iteration,Haskell,Fixpoint Combinators,Fixed Point Iteration,我正在寻找一个库,它将计算一个集合的不动点/闭包,该集合包含许多可变算术运算符。比如说, fixwith [(+)] [1] 对于整数,应计算所有N(自然数,1..)。我试着试着写它,但有些东西是不够的。它不是很有效,而且我感觉我对多重算术函数的处理不是最优雅的。此外,是否可以使用内置的fix函数而不是手动递归进行编写 class OperatorN α β | β -> α where wrap_op :: β -> (Int, [α] -> α) instanc

我正在寻找一个库,它将计算一个集合的不动点/闭包,该集合包含许多可变算术运算符。比如说,

fixwith [(+)] [1]
对于整数,应计算所有N(自然数,
1..
)。我试着试着写它,但有些东西是不够的。它不是很有效,而且我感觉我对多重算术函数的处理不是最优雅的。此外,是否可以使用内置的
fix
函数而不是手动递归进行编写

class OperatorN α β | β -> α where
    wrap_op :: β -> (Int, [α] -> α)

instance OperatorN α (() -> α) where
    wrap_op f = (0, \[] -> f ())

instance OperatorN α (α -> α) where
    wrap_op f = (1, \[x] -> f x)

instance OperatorN α ((α, α) -> α) where
    wrap_op f = (2, \[x, y] -> f (x, y))

instance OperatorN α ((α, α, α) -> α) where
    wrap_op f = (3, \[x, y, z] -> f (x, y, z))

instance OperatorN α ((α, α, α, α) -> α) where
    wrap_op f = (4, \[x, y, z, w] -> f (x, y, z, w))

type WrappedOp α = (Int, [α] -> α)
fixwith_next :: Eq α => [WrappedOp α] -> [α] -> [α]
fixwith_next ops s = List.nub (foldl (++) s (map g ops)) where
    g (0, f) = [f []]
    g (arity, f) = do
        x <- s
        let fx = \xs -> f (x:xs)
        g (arity - 1, fx)
fixwith ops s
    | next <- fixwith_next ops s
    , next /= s
    = fixwith ops next
fixwith _ s = s
设定版本 虽然我想我只需要弄清楚如何减少计算量,使它实际上更快,但这并不能提高性能

import qualified Control.RMonad as RMonad

class OperatorN α β | β -> α where
    wrap_op :: β -> (Int, [α] -> α)

instance OperatorN α (() -> α) where
    wrap_op f = (0, \[] -> f ())

instance OperatorN α (α -> α) where
    wrap_op f = (1, \[x] -> f x)

instance OperatorN α ((α, α) -> α) where
    wrap_op f = (2, \[x, y] -> f (x, y))

instance OperatorN α ((α, α, α) -> α) where
    wrap_op f = (3, \[x, y, z] -> f (x, y, z))

instance OperatorN α ((α, α, α, α) -> α) where
    wrap_op f = (4, \[x, y, z, w] -> f (x, y, z, w))

type WrappedOp α = (Int, [α] -> α)

fixwith_next :: Ord α => [WrappedOp α] -> Set α -> Set α
fixwith_next ops s = Set.unions $ s : map g ops where
    g (0, f) = RMonad.return $ f []
    g (arity, f) = s RMonad.>>= \x ->
        g (arity - 1, \xs -> f (x:xs))
fixwith' ops s
    | next <- fixwith_next ops s
    , next /= s
    = fixwith' ops next
fixwith' _ s = s
fixwith ops s = Set.toList $ fixwith' ops (Set.fromList s)
范例

> take 3 $ fixwith [next_values (+2)] (Set.fromList [1])
[1,3,5]

我不得不失去一元操作,但这并不是交易杀手。

不,
fix
是一个骗局。它计算的是一种不同于你的定点

你对arity的处理非常务实。有许多不同的方法可以使它少一点锅炉板;看看这样的方法。我相信最终也会有人加入另一个令人兴奋的基于类型级别数字的解决方案

为了提高效率,我不确定仅使用
Eq
实例就可以做得更好。您可以考虑从调用的结果筛选出“代码> S/<代码>值,以调用(本地)<代码> G/<代码>函数,也就是说,让<代码> FixWixNave只返回新的元素。这应该会加快终止检查的速度,甚至可能使高效、懒惰的
fixwith
成为可能


如果您对严格性没有意见,并且需要一个
Ord
实例,那么使用real
Set
s也可能会提高效率。

您能详细说明一下吗?在我看来,如果你能避免它挂起,例如,通过知道元素的数量,你可以编写
take 2$fix(\x->List.nub$[1,2]++x)
。你可以使用
fix
,但它对
fix
的使用并不有趣。在Haskell中,
fix
相当于递归——您可以通过调用
fix
使任何递归定义非递归,并且您可以调用
fix
并用递归定义替换它。因此,问题“我可以在定义这个特定函数时使用
fix
吗?”相当于问题“我可以在定义这个特定函数时使用递归吗?”。答案是肯定的,但问题很傻,因为编写函数才是真正的目标,而是否使用递归是偶然的。
notin :: Ord α => Set α -> Set α -> Set α
notin = flip Set.difference

class Ord α => OperatorN α β | β -> α where
    next_values :: β -> Set α -> Set α

instance Ord α => OperatorN α (α -> α) where
    next_values f s = notin s $ s RMonad.>>= \x -> RMonad.return (f x)

instance Ord α => OperatorN α (α -> α -> α) where
    next_values f s = s RMonad.>>= \x -> next_values (f x) s

instance Ord α => OperatorN α (α -> α -> α -> α) where
    next_values f s = s RMonad.>>= \x -> next_values (f x) s

instance Ord α => OperatorN α (α -> α -> α -> α -> α) where
    next_values f s = s RMonad.>>= \x -> next_values (f x) s

-- bind lambdas with next_values
fixwith_next :: Ord α => [Set α -> Set α] -> Set α -> Set α
fixwith_next nv_bnd s = Set.unions $ map (\f -> f s) nv_bnd -- bound next values

fixwith' :: Ord α => [Set α -> Set α] -> Set α -> [α]
fixwith' ops s@(fixwith_next ops -> next)
    | Set.size next == 0 = []
    | otherwise = (Set.toList next) ++ fixwith' ops (Set.union s next)
fixwith ops s = (Set.toList s) ++ fixwith' ops s
fixwith_lst ops = fixwith ops . Set.fromList
> take 3 $ fixwith [next_values (+2)] (Set.fromList [1])
[1,3,5]