You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell中distinct函数归约规则及自动展开工具咨询

Haskell中distinct函数归约过程的自动展开工具需求

背景

我正在通过fp-course学习Haskell,已经实现了distinct函数,但对它的具体归约过程存疑,尤其是不确定State何时将集合传递给foldRight。我给相关函数添加了trace来追踪执行步骤,但手动展开代码很难和GHC的实际执行流程一致,希望找到能自动完成这种代码展开的工具。

带trace的相关代码

distinct ::
  Ord a =>
  List a
  -> List a
distinct as = trace "distinct" $ eval (filtering filterFunc as) S.empty
                where filterFunc a = trace "filterFunc" (State $ \set -> trace "state" (if S.member a set
                                                                                         then (False, set)
                                                                                         else (True, S.insert a set)))

eval ::
  State s a
  -> s
  -> a
eval st s = trace "eval" (fst' $ runState st s)

fst' = trace "fst" fst

doFunc f s = trace "doFunc" (f s)

runState ::
  State s a
  -> s
  -> (a, s)
runState (State f) s = trace "runState" (doFunc f s)

filtering ::
  Applicative k =>
  (a -> k Bool)
  -> List a
  -> k (List a)
filtering p = trace "filtering" (foldRight f (pure Nil))
                where f a = trace "filtering where" (lift2 (\b as -> bool as (a :. as) b) (p a))

foldRight :: (a -> b -> b) -> b -> List a -> b
foldRight _ b Nil      = b
foldRight f b (h :. t) = trace "foldRight" (f h (foldRight f b t))

执行结果

执行a = distinct (1 :. 2 :. 3 :. 3 :. 1 :. Nil :: List Int),最终得到结果1 :. 2 :. 3 :. Nil,trace输出如下:

>> a
distinct
eval
fst
runState
doFunc
filtering
foldRight
filtering where
runState
doFunc
runState
doFunc
filterFunc
state
foldRight
[1runState
doFunc
foldRight
filtering where
runState
doFunc
runState
doFunc
filterFunc
state
foldRight
,2runState
doFunc
foldRight
filtering where
runState
doFunc
runState
doFunc
filterFunc
state
foldRight
,3runState
doFunc
foldRight
filtering where
runState
doFunc
runState
doFunc
filterFunc
state
runState
doFunc
foldRight
filtering where
runState
doFunc
runState
doFunc
filterFunc
state
runState
doFunc
]

手动展开尝试(部分步骤)

distinct (1 :. 2 :. 3 :. 3 :. 1 :. Nil :: List Int)

------------------------------------------------------------------------------
| step 1: Expand distinct
| distinct as = trace "distinct" eval (filtering filterFunc as) S.empty
|  where filterFunc a = State $ \set -> if S.member a set
|                                       then (False, set)
|                                       else (True, S.insert a set)
------------------------------------------------------------------------------
eval (filtering filterFunc (1 :. 2 :. 1 :. Nil)) S.empty
  where filterFunc a = State $ \set -> if S.member a set
                                       then (False, set)
                                       else (True, S.insert a set)
                                       
------------------------------------------------------------------------------
| step 2: Expand eval
| eval st s = trace "eval" fst' $ runState st s
------------------------------------------------------------------------------
fst' (runState (filtering filterFunc (1 :. 2 :. 1 :. Nil)) S.empty)
  where filterFunc a = State $ \set -> if S.member a set
                                       then (False, set)
                                       else (True, S.insert a set)

------------------------------------------------------------------------------
| step 3: Expend fst
| (a, b) -> trace "fst" a
------------------------------------------------------------------------------
key
  where (key, value) = (runState (filtering filterFunc (1 :. 2 :. 1 :. Nil)) S.empty)
        filterFunc a = State $ \set -> if S.member a set
                                       then (False, set)
                                       else (True, S.insert a set)

------------------------------------------------------------------------------
| step 4: Expand runState
| runState (State f) s = trace "runState" (doFunc f s)
------------------------------------------------------------------------------
key
  where (key, value) = doFunc f s
        doFunc f s = (runState (filtering filterFunc (1 :. 2 :. 1 :. Nil)) S.empty)
        filterFunc a = State $ \set -> if S.member a set
                                       then (False, set)
                                       else (True, S.insert a set)

------------------------------------------------------------------------------
| step 5: Expand doFunc
| doFunc ff ss = trace "doFunc" (ff ss)
------------------------------------------------------------------------------
key
  where (key, value) = doFunc ff ss
        doFunc ff ss = ff ss
        ff ss = (runState (filtering filterFunc (1 :. 2 :. 1 :. Nil)) S.empty)
        filterFunc a = State $ \set -> if S.member a set
                                       then (False, set)
                                       else (True, S.insert a set)

------------------------------------------------------------------------------
| step 6: Expand filtering
| 
|  filtering p = trace "filtering" (foldRight f (pure Nil))
|                  where f a = trace "filtering where" (lift2 (\b as -> bool as (a :. as) b) (p a))
------------------------------------------------------------------------------
key
  where (key, value) = doFunc ff ss
        doFunc ff ss = ff ss

        ff ss = (runState (foldRight f (pure Nil) (1 :. 2 :. 1 :. Nil)) S.empty)
          where f a = lift2 (\b as -> bool as (a :. as) b) (p a)
        p = filterFunc

        filterFunc a = State $ \set -> if S.member a set
                                       then (False, set)
                                       else (True, S.insert a set)

------------------------------------------------------------------------------
| step 7: Expand foldRight
| 
| foldRight :: (a -> b -> b) -> b -> List a -> b
| foldRight _ b Nil      = b
| foldRight f b (h :. t) = trace "foldRight" (f h (foldRight f b t))
------------------------------------------------------------------------------
key
  where (key, value) = doFunc ff ss
        doFunc ff ss = ff ss

        ff ss = (runState (f 1 (foldRight f (pure Nil) (1 :. 2 :. 1 :. Nil))) S.empty)
          where f a = lift2 (\b as -> bool as (a :. as) b) (p a)
        p = filterFunc

        filterFunc a = State $ \set -> if S.member a set
                                       then (False, set)
                                       else (True, S.insert a set)

------------------------------------------------------------------------------
| step 8: Expand filtering where
| 
| 
| ff ss = (runState (f 1 (foldRight f (pure Nil) (1 :. 2 :. 1 :. Nil))) S.empty)
|   where f a acc = trace "filtering where" lift2 (\b as -> bool as (a :. as) b) (p a) acc
------------------------------------------------------------------------------
key
  where (key, value) = doFunc ff ss
        doFunc ff ss = ff ss

        ff ss = (runState expandFiltering S.empty)
          where expandFiltering = lift2 (\b as -> bool as (1 :. as) b) (filterFunc 1) (foldRight f (pure Nil) (1 :. 2 :. 1 :. Nil))

        filterFunc a = State $ \set -> if S.member a set
                                       then (False, set)
                                       else (True, S.insert a set)

问题

根据GHC的trace输出,state的执行位置和我的预期不符,手动展开代码很难对齐实际的执行流程。请问有什么工具可以自动完成这种代码展开操作?


内容的提问来源于stack exchange,提问作者zichao liu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 10:37:33