从haskell中的列表中提取

时间:2017-12-04 18:21:32

标签: haskell monads maybe

我对Haskell很陌生,并且不完全了解Maybe monads。

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和用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 .."

1 个答案:

答案 0 :(得分:3)

错误消息告诉您错误:

  

无法将预期类型“Hmm”与实际类型'[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

现在我们根本没有任何monadic元素(除了getVal :: Hmm -> IO (),但是......),你仍然会遇到和以前一样的问题。 yd被构建为Hmm,但您在其上唯一匹配的模式是查找[a]。此外,两种模式仅查找单元素列表,因此即使yd :: [Int]也不匹配。

让我们在模式匹配中使用Hmm构造函数重写并正确递归以捕获整个列表。我们还会重新编写getVal以返回String,因此我们甚至不必弄乱IO返回的putStr :: String -> IO () monad。

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包装的非空列表,每个结果但第一个是递归的。这将返回:

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并将其返回到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