I'm trying to convert several projects to classy-prelude
at the moment. While most behaviour seems quite straightforward to me, the (head . head)
gives mysterious errors on a simple 2D list.
Consider the following GHCi session:
Prelude> (head . head) [[1,2],[3,4]]
1
Let's try this with ghci -XNoImplicitPrelude
and classy-prelude
:
> import ClassyPrelude
ClassyPrelude> (head . head) [[1,2],[3,4]]
<interactive>:10:1:
Couldn't match type `MinLen (Succ nat1) mono1' with `[[t0]]'
Expected type: [[t0]] -> Element mono0
Actual type: MinLen (Succ nat1) mono1 -> Element mono0
The function `head . head' is applied to one argument,
but its type `MinLen (Succ nat1) mono1 -> Element mono0'
has only one
In the expression: (head . head) [[1, 2], [3, 4]]
In an equation for `it': it = (head . head) [[1, 2], [3, 4]]
I assume GHC simply can't resolve the types for multidimensional lists correctly. Is there any way I can help it without resorting to (Prelude.head . Prelude.head)
?
As already mentioned in the comments, classy prelude's head function only works on traversables which are guarranted to have at least one element by the type-system, so that it doesn't have to be partial. Because all your lists have at minimum one element, you can just use the non-empty list type:
head . head $ mlcons (mlcons 1 $ mlcons 2 $ toMinLenZero []) $ mlcons (mlcons 3 $ mlcons 4 $ toMinLenZero []) $ toMinLenZero [] :: Int
-- 1
(The functions starting with ml
are all from the MinLen module of mono-traversable
, which is reexported by classy-prelude
)
If you just want the behaviour of the Prelude.head
function, you can use unsafeHead again from the mono-traversable
package and exported by default:
unsafeHead . unsafeHead [[1,2],[3,4]]
-- 1
There is also headMay
in that module, which can be used if you like to handle failure differently and not crash the whole program.