如何分解 haskell 中的复杂类型别名?

How to break up complex type aliases in haskell?

我遇到了这个非常古老的数独代码,它对我来说似乎是希腊语,因为主要是这种丑陋的类型

type T = (Int,Int) -> [Int]

以理解这个函数为例

mark :: ((Int,Int),Int) -> T -> T
mark (p@(i,j),n) s q@(x,y) =
  if p==q then [n] else
  if x==i || y==j || e x i && e y j then delete n $ s q else s q
  where e a b = div (a-1) 3==div (b-1) 3

我可以把T换成实际的类型

mark :: ((Int,Int),Int) -> (Int,Int)->[Int] -> (Int,Int)->[Int]
mark (p@(i,j),n) s q@(x,y) = 

现在类型参数似乎没有正确排列。 p 完美匹配,但我对 "s" 感到困惑。如果我跳入对标记的调用,它是这样的......在这里我可以很容易地看到它的列表是键值对的数组,键值对的键像 (1,2) 等。这些已经在数独中被过滤为空白或零。

input :: String -> (Int,Int) -> [Int]
input s = foldr mark (const [1..9]) $
   [(p,n) | (p,n) <- zip idx $ map read $ lines s >>= words, n>0]

使用此列表和作为函数 (const [1..9]) 的累加器调用标记函数。这不符合类型签名。

mark :: ((Int,Int),Int) -> (Int,Int)->[Int] -> (Int,Int)->[Int]

代码的问题是我看不到标记函数的实际结果,我仍然不明白。当它传递给第三个函数时,它会得到一些输出。关于如何理解这个 sphagetti 代码的任何解释?

这种类型的值

type T = (Int,Int) -> [Int]

将任何数独单元格的坐标 (x,y) :: (Int,Int) 映射到此类单元格可能具有的一组可能值(表示为数字列表 [Int])。

函数const [0..9] 将任何单元格映射到所有数字的集合中。它充当数独求解器的初始状态:开始时,假设任何单元格可能有任何数字。