从 haskell 中的列表中提取

Extracting from a list in haskell

我是 Haskell 的新手,并不完全理解 Maybe monad。

data Hmm = Hmm [Maybe Int]
 deriving (Show, Eq)

yd = Hmm [Just 8, Just 5,Nothing,Just 2, Nothing, Just 2, Nothing,Nothing]

getVal = case yd of
  [Just val] -> putStr val
  [Nothing] -> putStr "."

我想通过将 Nothing 替换为一个点并将 Just n 替换为 n(全部在一行中)来提取我的列表。但是,这段代码给我一个错误。

Couldn't match expected type "Hmm" with actual type '[Maybe a0]'

In the pattern : [Nothing] 
In a case alternative: [Nothing] -> putStr "."
In the expression:
  case yd of
  [Just val] -> putStr val
  [Nothing] -> putStr "."

基本上我希望上面的列表采用“85.2.2..”格式

报错信息告诉你错误:

Couldn't match expected type "Hmm" with actual type '[Maybe a0]'

让我们通过使用 [Int] 而不是 [Maybe Int] 来简化,这样我们就可以将 monad 完全排除在外。让我们使用 0 代替 Nothingx 代替 Just x

来重写您的测试用例
data Hmm = Hmm [Int]
 deriving (Show, Eq)

yd = Hmm [8, 5, 0, 2, 0, 2, 0, 0]

getVal = case yd of
  [0] -> putStr "."
  [x] -> putStr $ show x
-- N.B. I had to reverse the order here since `[x]` will match before `[0]`.
-- This isn't an issue when you're still using Maybes, since Just x doesn't match Nothing

现在我们根本没有单子元素(getVal :: Hmm -> IO () 除外,但是...)您仍然会遇到与以前相同的问题。 yd 构造为 Hmm,但您在其上进行的唯一模式匹配是寻找 [a]。此外,这两种模式都只查找单元素列表,因此即使 yd :: [Int].

它们也不会匹配

让我们在模式匹配中使用 Hmm 构造函数重写并正确递归以捕获整个列表。我们还将重写 getVal 到 return 和 String,这样我们甚至不必弄乱 putStr :: String -> IO () [=53] 的 IO monad =]s.

import Data.Char (intToDigit)

data Hmm = Hmm [Int]
  deriving (Show, Eq)

yd = Hmm [8, 5, 0, 2, 0, 2, 0, 0]

getVal :: Hmm -> String
getVal (Hmm [])    = []
getVal (Hmm (0:xs) = '.'          : getVal (Hmm xs)
getVal (Hmm (x:xs) = intToDigit x : getVal (Hmm xs)

result :: String
result = getVal yd

注意我是如何在我的模式匹配中包含三个交替的。一个用于 Hmm [] -- 一个用 Hmm 类型包装的空列表,一个用于 Hmm (0:xs) -- 一个由第一个值为零的 Hmm 包装的非空列表,一个用于 Hmm (x:xs) —— 一个由 Hmm 包裹的非空列表,除第一个结果外,每个结果都是递归的。这将 return:

getVal yd =
getVal (Hmm (8:[5, 0, 2, 0, 2, 0, 0])) =
'8' : getVal (Hmm (5: [0, 2, 0, 2, 0, 0])) =
'8':'5' : getVal (Hmm (0: [2, 0, 2, 0, 0])) =
'8':'5':'.' : getVal (Hmm (2: [0, 2, 0, 0])) =
'8':'5':'.':'2' : getVal (Hmm (0: [2, 0, 0])) =
'8':'5':'.':'2':'.' : getVal (Hmm (2: [0, 0])) =
'8':'5':'.':'2':'.':'2' : getVal (Hmm (0: [0])) =
'8':'5':'.':'2':'.':'2':'.' : getVal (Hmm (0:[])) =
'8':'5':'.':'2':'.':'2':'.':'.': getVal (Hmm []) =   -- base case!
'8':'5':'.':'2':'.':'2':'.':'.':[] =      -- re-write as list
['8', '5', '.', '2', '.', '2', '.', '.']  -- re-write as String
"85.2.2.."

请注意,这只是:

toString :: Hmm -> String
toString (Hmm xs) = map f xs where
  f 0 = '.'
  f x = intToDigit x

要在此处使用 Maybe Int 并将此 return 用于 monad 世界,只需对您的代码应用相同的更改

import Data.Char (intToDigit)

data Hmm = Hmm [Maybe Int]
  deriving (Show, Eq)

yd = Hmm [Just 8, Just 5, Nothing, Just 2, Nothing, Just 2, Nothing, Nothing]

getVal :: Hmm -> String
getVal (Hmm []) = []
getVal (Hmm (Nothing:xs)) = '.'          : getVal (Hmm xs)
getVal (Hmm (Just x :xs)) = intToDigit x : getVal (Hmm xs)

-- or equivalently

getVal' :: Hmm -> String
getVal' (Hmm xs) = map f xs where
  f Nothing = '.'
  f (Just x) = intToDigit x