从haskell中的列表中提取

从haskell中的列表中提取,haskell,monads,maybe,Haskell,Monads,Maybe,我对Haskell是个新手,不太了解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 "." 我想提取我的列表,在一行中用点代替零,用

我对Haskell是个新手,不太了解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 "."
我想提取我的列表,在一行中用点代替零,用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的格式

错误消息告诉您错误:

无法将预期类型Hmm与实际类型“[可能是a0]”匹配

让我们通过使用[Int]而不是[Maybe Int]来简化,这样我们就可以完全消除单子。让我们重新编写测试用例,使用0代替0,使用x代替x

现在除了getVal::Hmm->IO之外,我们没有任何一元元素,但是。。。你仍然会遇到和以前一样的问题。yd被构造成一个Hmm,但是你在它上面做的唯一模式匹配就是寻找[a]。此外,这两种模式都只查找单个元素列表,因此即使yd::[Int],它们也不会匹配

让我们在模式匹配中使用Hmm构造函数重新编写,并正确递归以捕获整个列表。我们还将重写getVal以返回字符串,这样我们甚至不必处理putStr::String->IO返回的IO monad

请注意,我如何在模式匹配中包含三个备选方案。一个用于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

那么,什么错误?以及,就这一点而言,什么代码?如果你得到一个错误,你应该总是在你的问题中包含错误。你想用一个。或者你想打印一张照片。?你的代码和你对代码的描述说明了两件不同的事情。编译器会准确地告诉你出了什么问题。yd有Hmm类型,但模式[Nothing]只匹配任何类型a的[a]类型。为了在表达式yd::Hmm上进行模式匹配,必须在Hmm构造函数上进行模式匹配。注:这与单子无关。非常感谢您的解释和时间。你能解释一下最后一个位图f吗,因为它看起来是一个很好的优雅的方法,但是仅仅17个怎么样?另外,cf.@WillNess您可以收集为[String]并使用interlate退出函数,但这最终是一个不同的问题,不是吗?@BrandonAjax-map的类型是a->b->[a]->[b]。你正在传递一个[Maybe Int]并且想要返回一个[Char],这就是你的a和b。函数f将所有Nothing都转换为''.'s,而所有xs都转换为intToDigit x。正如Willence所指出的,对于任何x>16 intToDigit 17抛出异常,这都将失败,但也不清楚在这种情况下适当的输出是什么,getVal$Hmm[Just 17]与getVal$Hmm[Just 1,Just 7]有何不同?如上所述:对于任何x>=16,这都将失败
toString :: Hmm -> String
toString (Hmm xs) = map f xs where
  f 0 = '.'
  f x = intToDigit x
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