参考透明度和保护

All*_*nds 6 haskell

学习你一个 Haskell 为伟大的利益!我有:

ghci> [1..50] >>= (\x -> guard ('7' `elem` show x) >> return x)
[7,17,27,37,47]
Run Code Online (Sandbox Code Playgroud)

我将示例更改为:

ghci> [1..50] >>= (\x -> if x > 25 then [] else [()] >> return x)
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好。但现在我想要其他 25 个数字:

ghci> [1..50] >>= (\x -> if x > 25 then [()] else [] >> return x)

<interactive>:204:2: error:
    • No instance for (Num ()) arising from the literal ‘1’
    • In the expression: 1
      In the first argument of ‘(>>=)’, namely ‘[1 .. 50]’
      In the expression:
        [1 .. 50] >>= (\ x -> if x > 25 then [()] else [] >> return x)
Run Code Online (Sandbox Code Playgroud)

我可以像这样解决它:

ghci> [1..50] >>= (\x -> if x < 26 then [] else [()] >> return x)
[26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50]
Run Code Online (Sandbox Code Playgroud)

我的问题如下:我认为由于引用透明性,我可以用 if ... then ... else 子句替换守卫。通过上述例子的证明,除了“[()]”在子句中是第一个的情况外,它似乎有效。为什么是这样?我试图更深入地了解这里发生的事情。我对 Haskell 的机制很感兴趣。这在某种程度上感觉不一致。我对你的回答很感兴趣。

Wil*_*sem 9

失败的原因是因为现在编译器将其读取为:

(\x -> if x > 25 then [()] else ([] >> return x))
Run Code Online (Sandbox Code Playgroud)

这很重要,因为该else部分将在此处返回Ints (so [Int])列表,而该then部分将返回“单元”类型()(so [()])列表,当然这两个不匹配。由于一个if- then-else应该返回相同类型的值均thenelse条款,因此,它说,除非()是一个Num类型(例如,它可以分析150等该类型),我们有一个问题。

所以>> return xelse …条款的一部分。通过添加括号,您可以获得相同的结果:

(\x -> (if x > 25 then [()] else []) >> return x)
Run Code Online (Sandbox Code Playgroud)

例如:

Prelude> [1..50] >>= (\x -> (if x > 25 then [] else [()]) >> return x)
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]
Prelude> [1..50] >>= (\x -> (if x > 25 then [()] else []) >> return x)
[26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50]
Run Code Online (Sandbox Code Playgroud)