Haskell 为“Cons a”执行“concat”`

Haskell 为“Cons a”执行“concat”`,haskell,Haskell,我正在看一个实现实例Monad[]的练习。但是,我希望在给出以下定义的情况下实现Monad Cons: 数据Cons a=Cons a Cons a |空 我试图实现concat的等效功能,但我称之为扁平化: 但后来我对[a]如何映射到Cons a Cons a感到困惑 请给我一个提示,让我写出flatte的其余部分。为了防止我的大脑爆炸,我首先定义一个函数,它将两个Cons a项组合在一起 然后我将定义一个Cons,一个foldl的版本 最后,以显而易见的方式将其扩展到concat consC

我正在看一个实现实例Monad[]的练习。但是,我希望在给出以下定义的情况下实现Monad Cons:

数据Cons a=Cons a Cons a |空

我试图实现concat的等效功能,但我称之为扁平化:

但后来我对[a]如何映射到Cons a Cons a感到困惑


请给我一个提示,让我写出flatte的其余部分。

为了防止我的大脑爆炸,我首先定义一个函数,它将两个Cons a项组合在一起

然后我将定义一个Cons,一个foldl的版本

最后,以显而易见的方式将其扩展到concat

consConcat = consFoldl consPlus Empty
另一种避免大脑爆炸的方法是这样定义Cons a

data Cons a = a ::: Cons a | Empty
infixr 8 :::
区别只是语法,但更容易阅读

(1:::2:::Empty):::(3:::Empty):::Empty
比这个

Cons (Cons 1 (Cons 2 Empty)) (Cons (Cons 3 Empty) Empty)

为了不让我的大脑爆炸,我首先定义一个函数,它将两个Cons和a项组合在一起

然后我将定义一个Cons,一个foldl的版本

最后,以显而易见的方式将其扩展到concat

consConcat = consFoldl consPlus Empty
另一种避免大脑爆炸的方法是这样定义Cons a

data Cons a = a ::: Cons a | Empty
infixr 8 :::
区别只是语法,但更容易阅读

(1:::2:::Empty):::(3:::Empty):::Empty
比这个

Cons (Cons 1 (Cons 2 Empty)) (Cons (Cons 3 Empty) Empty)

其实很简单。concat函数通常定义如下:

concat :: [[a]] -> [a]
concat = foldr (++) []

foldr :: (a -> b -> b) -> b -> [a] -> b
foldr _ a []     = a
foldr f a (x:xs) = f x (foldr f a xs)

(++) :: [a] -> [a] -> [a]
[]     ++ ys = ys
(x:xs) ++ ys = x : xs ++ ys
instance Functor Cons where
    fmap _ Empty       = Empty
    fmap f (Cons x xs) = Cons (f x) (fmap f xs)

instance Monad Cons where
    return a = Cons a Empty
    m >>= f = flatten (map f m)
让我们分别调用这些函数的Cons版本flatte、reduceR和append:

flatten :: Cons (Cons a) -> Cons a
flatten = reduceR append Empty

reduceR :: (a -> b -> b) -> b -> Cons a -> b
reduceR _ a Empty       = a
reduceR f a (Cons x xs) = f x (reduceR f a xs)

append :: Cons a -> Cons a -> Cons a
append Empty       ys = ys
append (Cons x xs) ys = Cons x (append xs ys)
与@jamshidh不同,我使用了右折叠而不是左折叠,因为++的实现方式是,a++b++c在计算上比a++b++c便宜

现在我们可以将Cons作为Monad的一个实例,如下所示:

concat :: [[a]] -> [a]
concat = foldr (++) []

foldr :: (a -> b -> b) -> b -> [a] -> b
foldr _ a []     = a
foldr f a (x:xs) = f x (foldr f a xs)

(++) :: [a] -> [a] -> [a]
[]     ++ ys = ys
(x:xs) ++ ys = x : xs ++ ys
instance Functor Cons where
    fmap _ Empty       = Empty
    fmap f (Cons x xs) = Cons (f x) (fmap f xs)

instance Monad Cons where
    return a = Cons a Empty
    m >>= f = flatten (map f m)

简单。试着让Cons成为ApplicationandAlternative next的一个实例。

其实很简单。concat函数通常定义如下:

concat :: [[a]] -> [a]
concat = foldr (++) []

foldr :: (a -> b -> b) -> b -> [a] -> b
foldr _ a []     = a
foldr f a (x:xs) = f x (foldr f a xs)

(++) :: [a] -> [a] -> [a]
[]     ++ ys = ys
(x:xs) ++ ys = x : xs ++ ys
instance Functor Cons where
    fmap _ Empty       = Empty
    fmap f (Cons x xs) = Cons (f x) (fmap f xs)

instance Monad Cons where
    return a = Cons a Empty
    m >>= f = flatten (map f m)
让我们分别调用这些函数的Cons版本flatte、reduceR和append:

flatten :: Cons (Cons a) -> Cons a
flatten = reduceR append Empty

reduceR :: (a -> b -> b) -> b -> Cons a -> b
reduceR _ a Empty       = a
reduceR f a (Cons x xs) = f x (reduceR f a xs)

append :: Cons a -> Cons a -> Cons a
append Empty       ys = ys
append (Cons x xs) ys = Cons x (append xs ys)
与@jamshidh不同,我使用了右折叠而不是左折叠,因为++的实现方式是,a++b++c在计算上比a++b++c便宜

现在我们可以将Cons作为Monad的一个实例,如下所示:

concat :: [[a]] -> [a]
concat = foldr (++) []

foldr :: (a -> b -> b) -> b -> [a] -> b
foldr _ a []     = a
foldr f a (x:xs) = f x (foldr f a xs)

(++) :: [a] -> [a] -> [a]
[]     ++ ys = ys
(x:xs) ++ ys = x : xs ++ ys
instance Functor Cons where
    fmap _ Empty       = Empty
    fmap f (Cons x xs) = Cons (f x) (fmap f xs)

instance Monad Cons where
    return a = Cons a Empty
    m >>= f = flatten (map f m)

简单。试着让Cons成为ApplicationandAlternative next的一个实例。

@dfeur-部分有帮助,但我仍然觉得很难阅读,因为a。这是文字,b。我想你无法摆脱多余的帕伦夫妇。。。。有没有办法在Cons上使用infixr?是的,infixr 5“Cons”,但使用反勾号而不是单引号。@dfeuer-嘿,酷,我喜欢它!今天我学到了一些东西。。。。虽然我仍然喜欢这里的:::运算符:@dfeur您可以通过使用反斜杠:infixr 5`Cons`对注释进行转义来在注释中键入反斜杠。@dfeur-有部分帮助,但我仍然发现它很难阅读,因为a。这是文字,b。我想你无法摆脱多余的帕伦夫妇。。。。有没有办法在Cons上使用infixr?是的,infixr 5“Cons”,但使用反勾号而不是单引号。@dfeuer-嘿,酷,我喜欢它!今天我学到了一些东西。。。。尽管我仍然喜欢这里的:::运算符:@dfeuer您可以通过使用反斜杠转义在注释中键入反斜杠:infixr 5`Cons`。因此,可能会让您感到困惑的是,Cons一词的双重使用;try data List a=Cons a List a | Empty。例如,如果您编写的表达式[a]现在将被写为空;[a,b]作为Cons a Cons b Empty,依此类推。您可以不使用foldr和++等其他原语,只需在一个模式匹配处遍历列表和列表中的列表,并发出您看到的每个x:展平xss=case xss of Empty->Empty;Cons空xss'->展平xss';Cons Cons x xs xss'->Cons x flatten Cons xs xss'.因此,可能会让您感到困惑的是Cons这个词的双重使用;try data List a=Cons a List a | Empty。例如,如果您编写的表达式[a]现在将被写为空;[a,b]作为Cons a Cons b Empty,依此类推。您可以不使用foldr和++等其他原语,只需在一个模式匹配处遍历列表和列表中的列表,并发出您看到的每个x:展平xss=case xss of Empty->Empty;Cons空xss'->展平xss';Cons Cons x xs xss'->Cons x展平Cons xs xss'。