【问题标题】:Haskell: No instance of (Num ()) - defining my own monadic loopHaskell:没有 (Num ()) 的实例 - 定义我自己的一元循环
【发布时间】:2018-10-26 05:46:28
【问题描述】:

我正在 Haskell wiki 中尝试这个练习:https://en.wikibooks.org/wiki/Haskell/Higher-order_functions

下面的练习结合了你所学到的更高层次的知识 顺序函数、递归和 I/O。我们将重建什么是 在命令式语言中称为 for 循环。实现一个功能

for :: a -> (a -> Bool) -> (a -> a) -> (a -> IO ()) -> IO () 
for i p f job = -- ???

目前为止:

-- for : init value, end condition function, increment function, IO function, 
--       returns IO action

generate :: a -> (a->Bool) -> (a->a) -> [a]
generate s cnd incr = if (cnd s) then [] else [s] ++ generate (incr s) cnd incr

printToList  = do
               u <- print 1
               v <- print 2
               return [u,v]

ioToASingle :: [IO a] -> IO [a]
ioToASingle (x:xs) = do
                 x' <- x
                 return [x']

sequenceIO :: [IO a] -> IO [a]
sequenceIO [] = return []
sequenceIO (x:xs) = do
                     x' <- x
                     xs' <- sequenceIO xs
                     return ([x'] ++ xs')

for::a->(a->Bool)->(a->a)->(a->IO())->IO()
for s cnd incr ioFn = sequence_ (map (ioFn) (generate s cnd incr))

for'::a->(a->Bool)->(a->a)->(a->IO a)->IO [a]
for' s cnd incr ioFn = sequenceIO (map (ioFn) (generate s cnd incr))

for 工作正常:

for 1 (\i->i==10) (\i->i+1) (print)
1
2
3
4
5
6
7
8
9

for' 出现错误:

*Main> for' 1 (\i->i==10) (\i->i+1) (print)

<interactive>:323:6: error:
    • No instance for (Num ()) arising from the literal ‘1’
    • In the first argument of ‘for'’, namely ‘1’
      In the expression: for' 1 (\ i -> i == 10) (\ i -> i + 1) (print)
      In an equation for ‘it’:
          it = for' 1 (\ i -> i == 10) (\ i -> i + 1) (print)
*Main>

我不知道出了什么问题。

【问题讨论】:

  • (print) 的类型是Show a =&gt; a -&gt; IO (),而不是Show a =&gt; a -&gt; IO a。你需要将它与其他东西结合起来,让它返回输入。

标签: loops haskell types monads higher-order-functions


【解决方案1】:

这是你写的:

    for' :: a -> (a -> Bool) -> (a -> a ) -> (a -> IO a ) -> IO [a]
    for'    s    cnd            incr         ioFn         =  sequenceIO (map (ioFn) ...

*Main> for' 1    (\i->i==10)    (\i->i+1)    (print     )      
            a                                (a -> IO ())
                                             ------------
            ()                                      a ~ ()

因此1 :: (Num a) =&gt; a ~ (Num ()) =&gt; ()。但是() 类型没有Num 实例。

这是 GHC 的迂回方式告诉你,你需要一个 a -&gt; IO a 类型的函数,而不是 a -&gt; IO ()

Hindley-Milner 允许使用“更窄”的类型进行统一,但如果不这样做会更好——错误消息会更清晰。

无论如何,很容易想出你自己的——返回print,比如

myprint :: a -> IO a
myprint x = do { print x      -- or,  print x >> return x
               ; return x 
               }

【讨论】:

  • @luqui 谢谢;空白是一个重要的工具。在 Lisp 中也是如此。
【解决方案2】:

sequenceIO 返回类型是 IO [a],但 ioFn(如 for' 的定义)是返回 IO() 的“print”。您需要 ioFn 来返回 IO a,因此 sequenceIO 的返回将是 IO [a]。

例如尝试“return”而不是“print”,然后打印该值。 "return" 是 haskell 中的一个函数,它简单地将传递的参数转换为 monad,在本例中为 IO monad。

main = do p <- for' 1 (\i->i==10) (\i->i+1) (return) 
         print(p) 

这将打印 1 到 9 个数字的简单列表。

或者

p :: Int -> IO [Int]
p x =  for' 1 (\i->i==x) (\i->i+1) (return)

main = do y <- p 10
         print (y)  

【讨论】:

  • 你的意思是“ioFn 返回IO a”。
  • 另外,你的缩进是错误的。您需要更正它,或添加明确的{ ; } 分隔符,或两者
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多