Haskell 优雅的前奏曲(头,头)

Haskell 优雅的前奏曲(头,头),haskell,classy-prelude,Haskell,Classy Prelude,目前我正在尝试将几个项目转换为。虽然大多数行为对我来说都很简单,但是(head.head)在一个简单的2D列表中给出了神秘的错误 审议以下GHCi会议: Prelude> (head . head) [[1,2],[3,4]] 1 让我们用ghci-XNoImplicitPrelude和classy prelude试试这个: > import ClassyPrelude ClassyPrelude> (head . head) [[1,2],[3,4]] <inter

目前我正在尝试将几个项目转换为。虽然大多数行为对我来说都很简单,但是
(head.head)
在一个简单的2D列表中给出了神秘的错误

审议以下GHCi会议:

Prelude> (head . head) [[1,2],[3,4]]
1
让我们用
ghci-XNoImplicitPrelude
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]]
>导入classyprellude
classyprellude>(head.head)[[1,2],[3,4]]
:10:1:
无法将类型“MinLen(Succ nat1)mono1”与“[[t0]]”匹配
预期类型:[[t0]]->0元素
实际类型:MinLen(succnat1)mono1->Element mono0
函数名为“head”。“head”应用于一个参数,
但是它的类型是'MinLen(succnat1)mono1->Element mono0'
只有一个
在表达式中:(head.head)[[1,2],[3,4]]
在‘it’的方程式中:it=(head.head)[[1,2],[3,4]]

我假设GHC无法正确解析多维列表的类型。有没有什么方法可以不借助于
(Prelude.head.Prelude.head)

正如在评论中已经提到的,classy Prelude的函数只适用于类型系统保证至少有一个元素的可遍历项,因此它不必是局部的。因为所有列表至少有一个元素,所以您可以使用非空列表类型:

head . head $ mlcons (mlcons 1 $ mlcons 2 $ toMinLenZero []) $ mlcons (mlcons 3 $ mlcons 4 $ toMinLenZero []) $ toMinLenZero [] :: Int
-- 1
(以
ml
开头的函数都来自
mono-traversable
模块,该模块由
classy prelude
重新导出)

如果您只想了解
Prelude.head
函数的行为,您可以从
mono-traversable
包中再次使用,并默认导出:

unsafeHead . unsafeHead [[1,2],[3,4]]
-- 1

该模块中还有
headMay
,如果您希望以不同的方式处理故障而不使整个程序崩溃,可以使用该模块。

MinLen(succnat1)mono1
=>我认为您需要一个非空列表类型there@MauricioScheffer你认为我到底需要一个非空列表在哪里
[[1,2],[3,4]
在两个维度上都是非空的,GHC应该能够从中派生出一个Int类型(它可以为
Prelude.head
)@UliKöhler我认为MauricioScheffer是对的。这些列表是非空的,但它们的类型不是“非空列表”类型。@DanielWagner你的意思是说,虽然
Prelude.head
作为一个非空列表,由于
错误而失败,
classy Prelude
试图通过将非空列表定义为不同的类型来解决这个问题?我认为这完全正确。回答很好,我也会加入headEx。这与
unsafeHead
之间的区别在于
unsafeHead
可能会导致某些数据类型的segfault(
Vector
ByteString
),而
headEx
保证会在空容器上引发异常。