Mit*_*ops 3 haskell haskell-prelude
我对另类的前奏感兴趣。我了解有很多选择:
我了解其中很多简单的问题是文本,而另一种问题是类似head错误的函数,而您可能更喜欢它们更安全。
但是,当我尝试使用这些替代方法时head,hmm中的行为似乎完全破坏了该功能,并且对我而言似乎不是一种改进。这里有些例子:
Prelude> head [1]
1
Prelude> head []
*** Exception: Prelude.head: empty list
Run Code Online (Sandbox Code Playgroud)
Foundation> head [1]
<interactive>:6:6: error:
• Couldn't match expected type ‘NonEmpty c’
with actual type ‘[Integer]’
• In the first argument of ‘head’, namely ‘[1]’
In the expression: head [1]
In an equation for ‘it’: it = head [1]
• Relevant bindings include
it :: foundation-0.0.21:Foundation.Collection.Element.Element c
(bound at <interactive>:6:1)
Foundation> head []
<interactive>:7:6: error:
• Couldn't match expected type ‘NonEmpty c’ with actual type ‘[a0]’
• In the first argument of ‘head’, namely ‘[]’
In the expression: head []
In an equation for ‘it’: it = head []
• Relevant bindings include
it :: foundation-0.0.21:Foundation.Collection.Element.Element c
(bound at <interactive>:7:1)
Run Code Online (Sandbox Code Playgroud)
Safe> head []
<interactive>:22:1: error: Variable not in scope: head :: [a0] -> t
Run Code Online (Sandbox Code Playgroud)
ClassyPrelude> head [1]
<interactive>:24:6: error:
• Couldn't match expected type ‘NonNull mono’
with actual type ‘[Integer]’
• In the first argument of ‘head’, namely ‘[1]’
In the expression: head [1]
In an equation for ‘it’: it = head [1]
• Relevant bindings include
it :: Element mono (bound at <interactive>:24:1)
Run Code Online (Sandbox Code Playgroud)
Relude> head [1]
<interactive>:27:6: error:
• Couldn't match expected type ‘NonEmpty a’
with actual type ‘[Integer]’
• In the first argument of ‘head’, namely ‘[1]’
In the expression: head [1]
In an equation for ‘it’: it = head [1]
• Relevant bindings include it :: a (bound at <interactive>:27:1)
Run Code Online (Sandbox Code Playgroud)
RIO> head [1]
<interactive>:7:1: error:
Variable not in scope: head :: [Integer] -> t
Run Code Online (Sandbox Code Playgroud)
Protolude> head [1]
Just 1
Protolude> head []
Nothing
Run Code Online (Sandbox Code Playgroud)
看起来不错-也可以用在尾巴上,对吗?
Protolude> tail [1]
<interactive>:12:1: error:
• Variable not in scope: tail :: [Integer] -> t
• Perhaps you meant ‘tails’ (imported from Protolude)
Protolude> tails [1]
[[1],[]]
Protolude> tails []
[[]]
Run Code Online (Sandbox Code Playgroud)
好吧,这并不是完全替代。
我为什么缺少更好的功能?为什么这些功能一旦失败就会被定义呢?
chi*_*chi 10
在大多数情况下,引入它们是因为它们在编译时而不是运行时失败。
The problem with Prelude.head is not (only) that it can fail. It is that it has to, since there is no way to take a list [a] and always produce an element a, since the input list might be empty. There is no easy fix that is a drop-in replacement, a radical change is needed.
A safer, and arguably better prelude can address this issue in one of the following ways:
remove head, so that the programmer won't use a dangerous tool. Any use of head will fail, at compile time. Not great, but OK.
restrict the input type, e.g. head :: NonEmptyList a -> a. This will be usable, but the programmer has to adapt the code so to guarantee that the input list is really non empty. Just passing a nonempty list won't do for the compiler -- the compiler wants a proof, and rightly so. The good news is that the previous code will be littered with compile errors, which will help the programmer spot the parts of the program which need to be fixed.
restrict the output type, e.g. head :: [a] -> Maybe a. This can be used just fine, but the programmer will need to cope with the different result type, and handle all the potential Nothings. Again, the compile time errors will help the programmer to identify where some fixes are needed.
In any case, the programmer has to modify the code. There's no way around it. However, once the compile time errors are resolved, the program is guaranteed to never produce head: empty list errors at runtime.