Haskell:如果x> 0,则为矩阵值分配唯一的char

问题描述 投票:1回答:1

所以我程序的目标是接收一个Int矩阵供输入,程序将所有大于0的数字转换为唯一的连续字符,而0转换为'_'(没关系,只是任何字符都不会按顺序)。

例如

main> matrixGroupings [[0,2,1],[2,2,0],[[0,0,2]]
[["_ab"],["cd_"],["__e"]]

我能达到的最好成绩是

[["_aa"],["aa_"],["__a"]]

使用:

matrixGroupings xss = map (map (\x -> if x > 0 then 'a' else '_')) xss

据我所知,我遇到的问题是让程序记住其上一个值,因此,当值检查> 0时,它将选择行中的下一个字符。尽管我一生都无法弄清楚该怎么做。

任何帮助将不胜感激。

haskell matrix increment
1个回答
1
投票

您的问题是一门古代艺术的实例:用标签。它至少可以追溯到Chris Okasaki,而我最喜欢的治疗方法是Jeremy Gibbons

正如您从这两个示例中所看到的,结构可能存在多种变化贴上标签。但是,在这种情况下,我想最直接的方法就是这样做。在哈斯克尔这真的很短。让我们潜入。

食谱是这样:

  • 为矩阵定义多态类型。必须是数字矩阵和字符矩阵都是合法的成员。
  • 提供Traversable类的实例。在很多情况下,它可能是自动生成的。
  • 选择一个喜欢的单子。一个简单的选择是State(实际上,这是我唯一的选择可以想到的。)
  • 在此monad中创建一个将数字输入字符的action
  • 通过此动作遍历矩阵。

让我们做饭!

  • 一种类型可能就这样简单:

    newtype Matrix a = Matrix [[a]] deriving Show
    

    内部列表完全有可能具有不相等的长度-这种类型不会保护我们避免制作“ ragged”矩阵。这是糟糕的设计。但是我要浏览现在。 Haskell提供了endless depth以供完善。此类型的足够好我们的需求在这里。

    我们可以立即定义一个矩阵示例:

    example :: Matrix Int
    example = Matrix [[0,2,1],[2,2,0],[0,0,2]]
    
  • 定义Traversable有多难? 0硬。

    {-# language DeriveTraversable #-}
    
    ...
    
    newtype Matrix a = Matrix [[a]] deriving (Show, Functor, Foldable, Traversable)
    

    Presto。

  • 我们从哪里获得标签?这是一个副作用。函数到达某处,需要一个标签流,带头,然后将尾巴放回超尺寸的口袋中。一种可以执行此操作的monad是State

  • 它是这样的:

    label :: Int -> State String Char
    label 0 = return '_'
    label x = do
        ls <- get
        case ls of
            [ ] -> error "No more labels!"
            (l: ls') -> do
                put ls'
                return l
    

    我希望代码能自我解释。当函数“ creates”的单值时,我们称其为“ effectful”或给定monad中的“ action”]。例如,print是一个动作,好吧,打印东西。这是一个效果。 label也是一个动作,尽管单子。比较并自己查看。

  • 现在我们准备准备解决方案:

    matrixGroupings m = evalState (traverse label m) ['a'..'z']
    

就是这个。

λ matrixGroupings example
Matrix ["_ab","cd_","__e"]

胃口好!

P.S。。我从你身上夺走了所有荣耀,这是不公平的。为了再次使事情变得有趣,我挑战您一个练习:您可以定义一个Traversable实例,以另一种顺序标记矩阵吗?先按列,然后按行?

© www.soinside.com 2019 - 2024. All rights reserved.