Haskell 递归函数中的类型匹配和IO问题
我遇到了一些问题,找不到原因。我目前正在使用GHCi portable的最新版本,但面对现实:这是我第一次使用Haskell,所以像往常一样,问题可能是用户,而不是系统 出现的问题包括:Haskell 递归函数中的类型匹配和IO问题,haskell,recursion,io,pattern-matching,type-mismatch,Haskell,Recursion,Io,Pattern Matching,Type Mismatch,我遇到了一些问题,找不到原因。我目前正在使用GHCi portable的最新版本,但面对现实:这是我第一次使用Haskell,所以像往常一样,问题可能是用户,而不是系统 出现的问题包括: 我不完全确定我得到了let x=0和xk->[(k,v)]->v之间的区别 findKey xs=snd。头过滤器(\(k,v)->key==k)$xs --检查给定状态是否在接受状态列表中 checkAcception::String->[String]->IO() checkAcception final
- 我不完全确定我得到了
和let x=0
其想法是让用户选择一个文件,从中加载定义(xk->[(k,v)]->v之间的区别 findKey xs=snd。头过滤器(\(k,v)->key==k)$xs --检查给定状态是否在接受状态列表中 checkAcception::String->[String]->IO() checkAcception finalState acceptingStates=do 让accept=any(=finalState)接受状态 如果接受 然后putStrLn“输入已接受!!” else putStrLn“输入被拒绝!!”
,就像一个符咒)。然后提示他输入FSM工作的一些输入。readDef
递归的
然后执行实际工作(也不工作…。changeState
最后,显示状态和转换的顺序,并检查最终状态是否为接受状态(
)checkAcceptance
现在,不要试图优化我所写的内容。我知道,定义建模的方式可以改进,我写的许多行可以使用一些高阶Haskell-foo编写得更短。但请帮我解决上面列出的问题(当然也请帮我解决问题)。
先谢谢你
最后一件事:我正在为我的大学的一个研讨会尝试一些Haskell,因此如果软件架构组的人在谷歌上搜索我的代码并阅读以下内容:Hi:)您只需将
函数的第二个子句更改为:changeState
我们1)删除了do,2)组合了let子句,3)将第二个出现的oldState变量重命名为oldState2。在Haskell中,我们不重新定义变量——我们只是创建一个具有新名称的变量。完整的代码可在此处获得: 当你写作时:changeState startState (x:xs) stateTransitions = let (currentState, oldStates) = changeState xs startState stateTransitions newState = findKey x (findKey currentState stateTransitions) oldStates2 = (oldStates ++ currentState ++ " -(" ++ [x] ++ ")-> ") in (newState, oldStates2)
(new, old) = changeState ...
你是说changeState是一个纯函数。如果您使用
您是说它是一个一元计算,当您调用它时,您需要使用箭头do定义
。。。return(…)changeState
let的理解正确吗?是否有明显的类型不匹配是我造成的?递归的想法正确吗?不,问题是
表示法和do
函数不做您认为它们做的事情。在Haskell中:return
并不表示函数应该结束(即使它最常见于函数的结尾);它只是意味着参数应该被包装在一个return
中。因为应用了所有参数的函数类型是(String,String),编译器认为您正在尝试使用以下内容:(在没有GHC扩展的情况下不会实际编译,如果使用,将抛出异常,因为我使用了Monad
) 但是编译器已经知道未定义的
与(String,String)->(String,String)
不匹配,因此它没有检查实例是否存在。 修复此问题会暴露出另一个问题:在同一个函数中定义两次a->(String,a)
,除非这两个定义在不同的范围内,否则在Haskell中不起作用 这是您的函数经过修改以正确编译,但我还没有对其进行测试oldStates
changeState :: String -> String -> [(String, [(Char,String)])] -> (String, String) changeState startState [] _ = (startState, "") changeState startState (x:xs) stateTransitions = let (currentState, oldStates) = changeState xs startState stateTransitions newState = findKey x (findKey currentState stateTransitions) oldStates' = (oldStates ++ currentState ++ " -(" ++ [x] ++ ")-> ") in (newState, oldStates')
请从头开始。写一个函数。确保它能够编译。测试一下。如果您遇到问题,请在此处询问有关一个函数的问题。然后继续下一步。在这里,你已经扔掉了一大堆乱七八糟的代码,并说“它不起作用。帮帮我。”没有太多人会有兴趣去挖掘所有这些。毫无疑问,你似乎在用字符串来表示LISP或Scheme程序员将使用符号的用途。在Haskell中,我们通常在可能的情况下尝试使用枚举类型。写一些类似于
。然而,在Haskell中通常有更自然的FSM表示。@dfeur就像我没有想到的那样。。。我很清楚,我张贴的不是一个简明的问题。但我想我指出,我不确定问题产生于代码的哪一部分,所以我最好把它全部发布出来。最重要的是,我经常阅读一些帖子,其中一个过短的问题会导致更多的问题,因为上下文甚至意思都不清楚。因此,为了改进我的请求:我特别不确定data FSMState=Start | Stop | A |…
部分。问题依然存在:我对changeState
在我看来毫无意义。据我所知,你根本不需要/想要一个changeState
块,我也不知道你说的“旧州”是什么意思。不是只有一个当前状态和一个下一个状态吗?是的,当然总是只有一个当前状态和一个下一个状态。但是,如果我想在命令行中打印正在使用的状态,即从开始状态到下一个状态的转换。。。到最后的状态,我看到两种方式:1。在递归函数中执行此操作。然后我需要将它定义为IO,但实际上我希望保持它的纯净。2.以递归方式构建一个字符串oldStates,我将随函数返回该字符串,稍后可以打印出来。do
(new, old) = changeState ...
(new, old) <- changeState ...
instance Monad ((,) String) where (>>=) = undefined :: (String,a) -> (a -> (String,b)) -> (String,b) return = undefined :: a -> (String,a)
changeState :: String -> String -> [(String, [(Char,String)])] -> (String, String) changeState startState [] _ = (startState, "") changeState startState (x:xs) stateTransitions = let (currentState, oldStates) = changeState xs startState stateTransitions newState = findKey x (findKey currentState stateTransitions) oldStates' = (oldStates ++ currentState ++ " -(" ++ [x] ++ ")-> ") in (newState, oldStates')