0

我有点不确定我正在尝试的实际名称是什么,创建折叠或变质似乎是它的名称。

我有以下折叠的数据结构:

type Order = [Int]
data Orders = Orders FilePath Order Order

type FoldOrders m o os = FilePath -> o -> o -> m os
type FoldOrder m o i = [i] -> m o
type FoldInt m i = Int -> m i

type Fold m os o i = (FoldOrders m o os, FoldOrder m o i, FoldInt m i)

foldOrders :: (Monad m) => Fold m os o i -> Orders -> m os
foldOrders (fos, fo, fi) (Orders orders1 orders2) = do o1 <- foldOrder orders1
                                                       o2 <- foldOrder orders2
                                                       fos o1 o2
    where foldOrder order = do o <- mapM foldInt order
                               fo o
          foldInt int     = fi int

此折叠适用于例如此“实现”:

simpleWrite :: Fold IO () () ()
simpleWrite = (fos, fo, fi)
where fos _ _ = return ()
      fo  _   = return ()
      fi  i   = putStrLn $ show i

使用此命令

foldOrders simpleWrite (Orders [1,2] [3,4])

1 2 3 4它会像您期望的那样打印出来。

到目前为止一切顺利,但是..

当我想在遍历数据结构时“下推”一些信息(在这种情况下为文件路径),如下所示:

write :: Fold IO a b c
write = (fos, fo, fi)
     where fos path fo1 fo2 = do _ <- fo1 path
                                 _ <- fo2 path
                                 return ()
           fo fis path = do ios <- mapM (\x -> x path) fis
                            return ()           
           fi int path = appendFile path $ show int

我无法编译它。它返回此错误:

Couldn't match type `FilePath -> IO ()' with `IO c'
Expected type: FoldInt IO c
  Actual type: Int -> FilePath -> IO ()
In the expression: fi

似乎您不能像这样返回部分单子函数,但这是为什么呢?我怎样才能让它工作?

4

1 回答 1

1

如果您想写入某个特定文件,那么该文件应该只是write函数的参数,即write :: FilePath -> Fold IO a b c. 但据我了解,您想根据实际数据计算文件路径。在这种情况下,文件路径取决于数据的大小,因此这是您需要计算的。您还需要计算类型的延续FilePath -> IO ()- 您有后者,但您缺少前者。

write :: Fold IO () (Int, FilePath -> IO ()) (FilePath -> IO ())
write = (fos, fo, fi) where 

 fos :: (Int, FilePath -> IO ()) -> (Int, FilePath -> IO ()) -> IO () 
 fos (sz1, fo1) (sz2, fo2) = do 
   let fp = show (sz1 + sz2) ++ ".txt" 
   sequence_ [fo1 fp, fo2 fp] 

 fo :: [ FilePath -> IO () ] -> IO (Int, FilePath -> IO ())
 fo fis = return (length fis, \fp -> mapM_ ($ fp) fis)

 fi :: Int -> IO (FilePath -> IO ())
 fi int = return $ \fp -> appendFile fp (show int)

如您所见,原理很简单。如果您需要一次计算两件事,只需一次计算两件事!大小只是简单地添加,而类型的函数FilePath -> IO ()则简单地逐点提升然后排序。

和一个测试(在 ghci 中):

>:! cat 4.txt
cat: 4.txt: No such file or directory
>foldOrders write  (Orders [1,2] [3,4])
>:! cat 4.txt
1234>foldOrders write  (Orders [1,2] [3,4])
>:! cat 4.txt
12341234>
于 2015-12-22T16:54:27.387 回答