Haskell 使用maybe进行列表渲染错误的模式匹配

Haskell 使用maybe进行列表渲染错误的模式匹配,haskell,pattern-matching,maybe,Haskell,Pattern Matching,Maybe,分解模式时,我应该如何使用Just构造函数? 例如:如果我的模式是:(x1,x2,x3,.xn)我将不得不用它的将模式的每个元素括起来 我的问题:我正在尝试“安全地”实现Init函数。我是否必须在第二行中对尾部和头部使用 safeInit::[a]->Maybe [a] safeInit (x:xs)=x: safeInit (Just xs) #Just x : safeInit Just xs ? safeInit [x,y]=Just [x] safeInit _ =Nothing

分解模式时,我应该如何使用
Just
构造函数?
例如:
如果我的模式是:
(x1,x2,x3,.xn)
我将不得不用它的
将模式的每个元素括起来

我的问题:我正在尝试“安全地”实现Init函数。
我是否必须在第二行中对尾部和头部使用

safeInit::[a]->Maybe [a]
safeInit (x:xs)=x: safeInit (Just xs) #Just x : safeInit Just xs ?
safeInit [x,y]=Just [x]
safeInit _ =Nothing

这里有两个问题:

  • 你打电话时输入一个
    可能是[a]
    ;及
  • 第一个模式包含一个(严格的)超集,然后是第二个模式,因此第二个模式永远不会触发
对于第一个问题,罪魁祸首是:

safeInit (x:xs) = x: safeInit (Just xs)
在这里,
safeInit
,需要一个列表(键入
[a]
),但是您将列表包装在
Just
构造函数中,因此您向它传递了一个
Maybe[a]
值,而
safeInit
无法处理此问题。因此,我们可以将其改写为:

safeInit (x:xs) = x : safeInit xs
然而,这并不能解决问题,因为现在我们将
上的“cons”(
)称为a
,并且
可能[a]
,同样,函数无法处理此问题。我们首先必须检查递归调用是否生成一个
safeInit
,然后在
x
前面加上一个
Just
,我们可以使用
fmap

safeInit (x:xs) = fmap (x:) (safeInit xs)
对于第二个问题,我们可以重新安排条款:

safeInit :: [a] -> Maybe a
safeInit [x, _] = Just [x]
safeInit (x:xs) = fmap (x:) (safeInit xs)
safeInit [] = Nothing
尽管如此,这种方法仍然存在一些问题:它相当低效,因为我们只为所有元素(最后一个除外)展开并包装
元素,因为它没有得到优化。此外,如果我们处理一个无限列表,我们将陷入一个无限循环。我们可以通过使用一个内部函数来改进它,该函数计算
init
,因为我们确信
init
是有效的。例如:

safeInit :: [a] -> Maybe a
safeInit (x:xs) = Just (go x xs)
    where go _ [] = []
          go x (x2:xs) = x : go x2 xs
safeInit [] = Nothing

这取决于你想要什么语义学。在
init
的情况下,一旦找到任何元素,就知道结果实际上是
Just
,即
Just initxs
。然后,您希望将当前的
x
添加到包含的列表中,而不更改
的任何内容,只更改
。最简单的方法是使用
Maybe
Functor
实例:

safeInit (x:xs) = (x:) <$> safeInit xs

扩展Elmex80的建议

safeInit :: [a] -> Maybe [a]
safeInit [] = Nothing
safeInit xs = Just (init xs)

使用
safeInit(x:xs)=Just(init(x:xs))
。我不想使用开箱即用的方法。不过还是要谢谢你。但是你不是这样更改初始列表吗?@bercoviciarian:你不能更改Haskell中的任何内容,所有变量都是不可变的。你认为我在以什么方式改变初始列表?不,你没有改变我以为你是在x后面加x…你只是在用“x2”进一步分解。我很抱歉。
safeInit (x:xs) = case safeInit xs of
      Just init_xs -> Just $ x : init_xs
      Nothing -> Just []
safeInit [] = Nothing
safeInit :: [a] -> Maybe [a]
safeInit [] = Nothing
safeInit xs = Just (init xs)