我有大量的IConnection conn => conn - > IO()函数,我需要执行这些函数来正确设置数据库.现在,它并不是很漂亮,但我在Haskell中太过初衷,无法让它变得更好.
setup :: IConnection conn => conn -> IO ()
setup conn = do
setupUtterances conn
commit conn
setupSegments conn
commit conn
setupLevels conn
commit conn
setupLevelLevel conn
commit conn
setupTCLevelLevel conn
commit conn
setupPaths conn
commit conn
setupLabelTypes conn
commit conn
setupLegalLabels conn
commit conn
setupTracks conn
commit conn
setupVariables conn
commit conn
setupFeatures conn
commit conn
setupAssociations conn
commit conn
return ()
Run Code Online (Sandbox Code Playgroud)
无论如何缩短它?我在玩
sequence $ map ($ conn) [func1, func2,...]
Run Code Online (Sandbox Code Playgroud)
但我无法让它发挥作用.建议?
我正在通过一些介绍性的Haskell材料,目前正在通过Monads.我从概念上理解>>=运算符的类型是:
(Monad m) => m a -> (a -> m b) -> m b.
在这种情况下,我很困惑为什么下面的代码工作,即为什么它不会导致类型不匹配:
main = getLine >>= \xs -> putStrLn xs
Run Code Online (Sandbox Code Playgroud)
因为我们知道getLine :: IO String,我认为它可以与类型函数"绑定" String -> IO String.但是putStrLn有不同的类型:putStrLn :: String -> IO ().
那么为什么Haskell允许我们使用>>=这两个函数呢?
TL; DR:
如何确保给定语句中randomRIO(from System.Random)生成的值的持久性do?
如何使用IO Monad中的可变结构?
我最初的问题是(非常)错误 - 我正在更新标题,以便将来想要理解在IO monad中使用可变结构的读者可以找到这篇文章.
更长的版本:
抬头:这看起来很长,但很多只是我概述了如何exercism.io运作.(更新:最后两个代码块是我的代码的旧版本,作为参考,以防未来的读者希望根据评论/答案跟随代码中的迭代.)
练习概述:
我正在Robot Name从(非常有教育意义的)exercism.io开始练习.练习涉及创建一个Robot能够存储名称的数据类型,该名称是随机生成的(练习Readme包括在下面).
对于那些不熟悉它的人,exercism.io学习模型基于学生生成的代码的自动测试.每个练习都包含一系列测试(由测试作者编写),解决方案代码必须能够通过所有测试.我们的代码必须通过给定练习的测试文件中的所有测试,然后我们才能进入下一个练习 - 一个有效的模型,imo.(Robot Name运动#20左右.)
在这个特殊的练习中,我们会要求创建一个Robot数据类型和三个附带功能:mkRobot,robotName和resetName.
mkRobot 生成一个实例 Robot robotName生成并"返回"未命名的唯一名称Robot(即,robotName不覆盖预先存在的名称); 如果Robot已有名称,则只返回现有名称resetName 用新的名称覆盖预先存在的名称.在这个特定的练习中,有7个测试.测试检查:
robotName生成符合指定模式的名称(名称长度为5个字符,由两个字母后跟三个数字组成,例如AB123,XQ915等)robotName是持久性的(即,假设我们创建机器人A并使用它来为他(或她)分配名称robotName; robotName第二次调用(在机器人A上)不应该覆盖他的名字)robotName为不同的机器人生成唯一的名称(即,它测试我们实际上是随机化过程)resetName生成符合指定模式的名称(类似于测试#0)resetName是持久的免责声明:我对Haskell有点新鲜.
大家好,
我正在写一个翻译,或者在这种情况下,写一个REPL.为此我使用haskeline,这对REPL很好.它具有将命令行历史存储在文件中的能力,这也很好.
但是,我在使用它时遇到的一个问题是它似乎没有将"〜"扩展到主目录,这意味着我必须手动检索主目录.
我可以这样做(目前也这样做):
-- | returns a fresh settings variable
addSettings :: Env -> Settings IO
addSettings env = Settings { historyFile = Just getDir
, complete = completeWord Nothing " \t" $
return . completionSearch env
, autoAddHistory = True
}
where
getDir :: FilePath
getDir = unsafePerformIO getHomeDirectory ++ "/.zepto_history"
Run Code Online (Sandbox Code Playgroud)
但是这种使用unsafePerformIO,这让我感到畏缩.您是否知道一个良好而干净的解决方法,不涉及重写整个功能?这可能是haskeline我不知道的功能或者我没看到的功能.
告诉我没有办法改写和重新思考它一切都很好.
编辑:
我知道unsafePerformIO很糟糕,这就是为什么它让我畏缩.如果你是Haskell的新手并且现在正在阅读这个问题:假装它不在那里.
假设代码
f :: IO [Int]
f = f >>= return . (0 :)
g :: IO [Int]
g = f >>= return . take 3
Run Code Online (Sandbox Code Playgroud)
当我g在ghci中运行时,它会导致stackoverflow.但我想也许它可以懒惰地评估并生产[0, 0, 0]包装IO.我怀疑这IO是责备,但我真的不知道.显然以下工作:
f' :: [Int]
f' = 0 : f'
g' :: [Int]
g' = take 3 f'
Run Code Online (Sandbox Code Playgroud)
编辑:事实上我对拥有这么简单的功能不感兴趣f,原始代码看起来更像是这样:
h :: a -> IO [Either b c]
h a = do
(r, a') <- h' a
case r of
x@(Left _) -> h …Run Code Online (Sandbox Code Playgroud) 潜入monad后,我明白它们是允许在某些上下文中链接计算的一般概念(失败,非确定性,状态等),并且它们背后没有任何魔力.
IO monad感觉即使不是魔术,但特别.
main函数运行上述观点的原因是什么?是什么让IO如此特别?
更新:在纯代码评估顺序无关紧要.但是在做IO时这很重要(我们希望在我们阅读之前保存客户).根据我的理解,IO monad为我们提供了这样的订购保证.它是一般monad的属性还是IO monad特有的东西?
考虑以下Haskell语句:
mapM print ["1", "2", "3"]
Run Code Online (Sandbox Code Playgroud)
实际上,这按顺序打印"1","2"和"3".
问:你怎么知道那mapM会先打印出"1",然后打印出"2",并最终打印出"3".有没有保证会这样做?或者它是如何在GHC深度实施的巧合?
在关于FFI的GHC手册部分中,声明程序员可以使用newtype在IO monad周围创建一个包装器monad,并在调用外部代码时使用它来代替IO monad.(GHC手册)
到目前为止,我有:
newtype PGm a = PGm (IO a)
instance Monad PGm where
(>>=) a b = ...
(>>) a b = ...
return a = PGm (return a) --I think
fail a = PGm (fail a) --I think
Run Code Online (Sandbox Code Playgroud)
关于如何实施(>>=)和实施,我感到很茫然(>>).
以下(工作)Haskell 程序输出随机拼写:
import System.Random
spells =
[ "Abracadabra!"
, "Hocus pocus!"
, "Simsalabim!"
]
main :: IO()
main = do
spell <- (spells !!) <$> randomRIO (0, length spells - 1)
putStrLn spell
Run Code Online (Sandbox Code Playgroud)
然而,这个变量spell是非常无用的。它存储从法术列表中选择的随机字符串,但随后会立即传递给putStrLn函数并且不再使用。我尝试将两个 IO 操作合并为一行,如下所示:
main = putStrLn <$> (spells !!) <$> randomRIO (0, length spells - 1)
Run Code Online (Sandbox Code Playgroud)
但我收到以下错误:
• Couldn't match type ‘IO ()’ with ‘()’
Expected type: Int -> ()
Actual type: Int -> IO ()
• In the first argument of ‘(<$>)’, …Run Code Online (Sandbox Code Playgroud) 我想知道如何IO [Int]在 GHCI 中映射一个。
?: :{
?| th :: IO [Int]
?| th = pure [1, 2, 3, 4]
?| :}
?: th
[1,2,3,4]
?: :t th
th :: IO [Int]
?: map (+2) th
• Couldn't match expected type ‘[b]’ with actual type ‘IO [Int]’
• In the second argument of ‘map’, namely ‘th’
In the expression: map (+ 2) th
Run Code Online (Sandbox Code Playgroud)
想要的结果:
?: res = map (+2) th -- <-- some working version of this
?: res …Run Code Online (Sandbox Code Playgroud)