Haskell 一个有趣的模式
我正在解决99个哈斯克尔问题。我已经成功地解决了问题21,当我打开时,提出了以下解决方案: 在列表中的给定位置插入元素 我发现模式Haskell 一个有趣的模式,haskell,design-patterns,Haskell,Design Patterns,我正在解决99个哈斯克尔问题。我已经成功地解决了问题21,当我打开时,提出了以下解决方案: 在列表中的给定位置插入元素 我发现模式(n+1)很有趣,因为它似乎是一种优雅的方式,可以将insertAt的基于1的参数转换为split的基于0的参数(它的函数来自前面的练习,基本上与splitAt相同)。问题是GHC没有发现这种模式那么优雅,事实上它说: 模式中的分析错误:n+1 我不认为写答案的人是愚蠢的,我想知道这种模式在Haskell中是否合法,如果合法,如何解决这个问题。我相信是的,当《99 H
(n+1)
很有趣,因为它似乎是一种优雅的方式,可以将insertAt
的基于1的参数转换为split
的基于0的参数(它的函数来自前面的练习,基本上与splitAt
相同)。问题是GHC没有发现这种模式那么优雅,事实上它说:
模式中的分析错误:n+1
我不认为写答案的人是愚蠢的,我想知道这种模式在Haskell中是否合法,如果合法,如何解决这个问题。我相信是的,当《99 Haskell问题》的作者写这个解决方案时,很可能也是如此,但它不再在Haskell中。请注意,您现在可以
例如:
{-# LANGUAGE ViewPatterns #-}
module Temp where
import Data.List (splitAt)
split :: [a] -> Int -> ([a], [a])
split = flip splitAt
insertAt :: a -> [a] -> Int -> [a]
insertAt x xs (subtract 1 -> n) = let (ys,zs) = split xs n in ys++x:zs
n+k
模式的问题可以追溯到Haskell中的一个设计决策,即通过名称的第一个字符来区分模式中的构造函数和变量。如果回到ML,一个公共函数定义可能如下所示(使用Haskell语法)
如您所见,在第一行的LHS上,从语法上讲,f
和nil
之间没有区别,但它们有不同的角色f
是需要绑定到map
的第一个参数的变量,nil
是需要与第二个参数匹配的构造函数。现在,ML通过在周围的范围中查找每个变量,并在查找失败时假设名称是变量,从而实现了这一区别。因此,当查找失败时,nil
被识别为构造函数。但是考虑一下当模式中有一个键入时会发生什么:
map f niil = nil
(在niil
中有两个i
s)niil
不是作用域中的构造函数名称,因此它被视为变量,并且定义被错误地解释
Haskell对此问题的解决方案是要求构造函数名以大写字母开头,变量名以小写字母开头。而且,对于中缀运算符/构造函数,构造函数名称必须以:
开头,而运算符名称不能以:
开头。这也有助于区分解构绑定:
x:xn = ...
显然是解构绑定,因为在
n - m = ...
显然是一个函数定义,因为-
不能是构造函数名
但是允许使用n+k
模式,比如n+1
,意味着+
既是一个有效的函数名,也是一个类似于模式中构造函数的东西。现在
n + 1 = ...
又是模棱两可,;它可以是名为(+)
的函数定义的一部分,也可以是n
的解构模式匹配定义。在Haskell 98中,通过声明
n + 1 = ...
函数定义,以及
(n + 1) = ...
解构绑定。但这显然不是一个令人满意的解决方案。尽管我认为
n+k
-模式确实有一定的吸引力,但在基于1的表示和基于零的表示之间进行转换将永远不是一个合适的用例。它们是用来递归地“解构”数字的FWIW,insertAt
无论如何应该是基于零的,不是吗?@leftaroundabout,insertAt
应该是基于1的,根据给定的示例:insertAt'X'”abcd“2
->“aXbcd”
。是的,我的意思是,它确实应该被指定为基于0的,就像所有Haskell标准列表函数一样()。
n + 1 = ...
(n + 1) = ...