foldFactor : Int -> T -> (Int -> Bool) -> (T -> Int -> Int) -> T foldFactor num init pred f = facList = factor num foldRest res base facID = if facID == len facList then f res base else (fac, cnt) = facList[facID] foldSingle res base usingCnt = if usingCnt > cnt || pred base then res else newRes = foldRest res base (facID + 1) foldSingle newRes (base * fac) (usingCnt + 1) foldSingle res base 0 foldRest init 1 0
如果只想获得所有除数,可以写成:
1 2 3 4 5
divs : Int -> [Int] divs num = factor num .map ((fac, cnt) => fac ** [0 to cnt]) .fold [1] (res => next => res * next)
其中 res * next 可以被语法糖成 res.bind (i => i * next),而 i * next 被进一步语法糖成 next.map (j => i * j)。
要正确编译这玩意特别考验编译器,暂时我还没想到怎么实现。
杂记
这题我先不用绷语言写了,感觉比较累。
最近关于绷语言有几个需要考虑的:
是否要引入有语义的类型?例如引入一个 Ans 类型表示答案,规定该类型被构造后是线性的,通过写一个 1 Ans -> T 的函数并自动织入来模拟仿射。
这样的好处是可以减少程序出错的可能性。当你想要构造出一个「答案」的时候,你不再是令一个名字是 ans 的变量为答案(这对编译器来说没有语义,因此它也不可能为你检查答案是否被正确输出),而是构造一个 Ans 类型的实例(这对编译器来说有语义,因为 Ans 类型的实例是线性的,且用户可以通过修改一个 1 Ans -> T 的函数来丰富 Ans 类型的语义。