A';反对意见';在Haskell中,它与对应的Scheme类似
作为练习,我在Haskell中实现了一个“cons”操作,它由任意类型的两个值组成一对。实现所需的数据类型非常简单:A';反对意见';在Haskell中,它与对应的Scheme类似,haskell,scheme,Haskell,Scheme,作为练习,我在Haskell中实现了一个“cons”操作,它由任意类型的两个值组成一对。实现所需的数据类型非常简单: data Nil = Nil deriving (Eq) data Pair a b = Cons a b deriving (Eq) car (Cons x _) = x cdr (Cons _ y) = y caar = car . car cdar = cdr . car cadr = car . cdr cddr = cdr . cdr *Main> cddr
data Nil = Nil deriving (Eq)
data Pair a b = Cons a b deriving (Eq)
car (Cons x _) = x
cdr (Cons _ y) = y
caar = car . car
cdar = cdr . car
cadr = car . cdr
cddr = cdr . cdr
*Main> cddr (Cons 55 (Cons (1,2,3,4) "hello, world!"))
"hello, world!"
*Main>
但受此启发,我想让结果对像Scheme列表一样打印出来——包括臭名昭著的“不正确列表”(1 2 3.4)。我的实现(见下文)适用于Char:
*Main> Cons 'a' (Cons 'b' (Cons 'c' Nil))
('a' 'b' 'c')
*Main> Cons 'a' (Cons 'b' 'c')
('a' 'b' . 'c')
*Main> Cons (Cons 'a' 'b')(Cons 'c' (Cons 'd' Nil))
(('a' . 'b') 'c' 'd')
对于Int(或任何其他数据类型)来说,它工作得不太好。所以我的问题是:我怎样才能使它适用于其他数据类型?i、 例如,我希望它能像这样工作:
*Main> Cons 5 (Cons "hello" (Cons False Nil))
(5 "hello" False)
我目前的全面执行情况如下:
data Nil = Nil deriving (Eq)
data Pair a b = Cons a b deriving (Eq)
car (Cons x _) = x
cdr (Cons _ y) = y
caar = car . car
cdar = cdr . car
cadr = car . cdr
cddr = cdr . cdr
instance Show Nil where show _ = "()"
class ShowPair a where
showRight::a->String
instance (Show a, ShowPair a, ShowPair b)=>Show (Pair a b) where
show (Cons car cdr) = "(" ++ (show car) ++ (showRight cdr) ++ ")"
instance (Show a, ShowPair a, ShowPair b)=>ShowPair (Pair a b) where
showRight (Cons car cdr) = " " ++ (show car) ++ (showRight cdr)
instance ShowPair Char where
showRight x = " . " ++ show x
instance ShowPair Int where
showRight x = " . " ++ show x
instance ShowPair Nil where
showRight _ = ""
这里有一个选择。首先,通过将此行放在文件顶部来启用这些扩展名:
{-# LANGUAGE FlexibleInstances, OverlappingInstances, UndecidableInstances#-}
接下来,删除Char
和Int
的ShowPair
实例
现在,为具有Show
的任何内容添加一个ShowPair
实例:
instance Show a => ShowPair a where showRight = (" . " ++) . show
现在,这可以确保作为Show
实例的任何类型a
也是ShowPair
的实例,通过将
前置到其正常字符串形式来显示。但是,如果某个类型具有更具体的ShowPair
实例(例如Nil
),Haskell将使用该实例
这不是标准Haskell的一部分,因此需要启用三种语言扩展。查看以获取有关为什么需要扩展的更多信息。本在问题的注释中提到了本机对类型,我将在本回答中使用它。我还将用Haskell单元类型
()
替换您的Nil
这有点超出你的要求,但我认为值得一提。在Haskell中很难在Scheme中捕获“列表”的概念,除非您“欺骗”并使用类似的扩展。这是因为从“纯”的、未扩展的Haskell的角度来看,很难(如果不是不可能的话)将所有Scheme列表指定为同一类型。这意味着,尽管Scheme允许您编写接受任何列表(正确或不正确)的函数,但在Haskell中您将很难做到这一点(并且有充分的理由;不正确的“列表”可能无论如何都不存在)
例如,您基本上选择使用(a,b)
作为Scheme-like对的类型。现在假设我们有这些方案列表:
(define zero '())
(define one '(1))
(define two '(1 2))
(define three '(1 2 3))
(define four '(1 2 3 4))
这里有一个简单的Haskell配对翻译,对应于您的操作方式:
zero :: ()
zero = ()
one :: (Integer, ())
one = (1, ())
two :: (Integer, (Integer, ()))
two = (1, (2, ()))
three :: (Integer, (Integer, (Integer, ())))
three = (1, (2, (3, ())))
four :: (Integer, (Integer, (Integer, (Integer, ()))))
four = (1, (2, (3, (4, ()))))
关键在于,在Scheme中,您可以轻松编写一个覆盖所有列表的函数:
(define (reverse list)
(foldl cons '() list))
(define (filter pred? list)
(foldr (lambda (elem rest)
(if (pred? elem)
(cons elem rest)
rest))
'()
list))
(define (foldl fn init list)
(if (null? list)
init
(foldl fn (fn (car list) init) (cdr list))))
(define (foldr fn init list)
(if (null? list)
init
(fn (car list)
(foldr fn init (cdr list)))))
在这个Haskell翻译中,您根本无法轻松地做到这一点,因为不同长度的“列表”具有不同的类型。当你考虑<代码>反转<代码>之间的差异时(这是一个长度为n的列表并产生长度n的列表)和<代码>过滤器< /代码>(它取长度n的列表并产生长度m的列表)。≤ Haskell自带了一个内置操作,可以从任意类型的两个值组成一对:
(a,b)
。如果您想像使用函数一样使用它,可以将其拼写为(,)a b
()
然后接受您的Nil
部分<代码>汽车然后拼写为fst
,cdr
是snd
@Ben明白了-我知道我可能在这里做一些车轮改造。有没有办法让用(,)生成的配对像方案列表一样打印出来?谢谢你的精彩解释和相关帖子的链接!嗯,是的-我知道在Haskell中为“whatever列表”实现filter
和reverse
会有多尴尬-尽管cadr、cddr等都很简单