Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell IO:将IO字符串转换为";“其他类型”;_Haskell_Binary Search Tree - Fatal编程技术网

Haskell IO:将IO字符串转换为";“其他类型”;

Haskell IO:将IO字符串转换为";“其他类型”;,haskell,binary-search-tree,Haskell,Binary Search Tree,我有一个Haskell程序,它将一个文件作为输入,并将其转换为二进制搜索树 import System.IO data Tree a = EmptyBST | Node a (Tree a) (Tree a) deriving (Show, Read, Eq) ins :: Ord a => a -> (Tree a) -> (Tree a) ins a EmptyBST = Node a EmptyBST EmptyBST ins

我有一个Haskell程序,它将一个文件作为输入,并将其转换为二进制搜索树

import System.IO    

data Tree a = EmptyBST | Node a (Tree a) (Tree a) deriving (Show, Read, Eq)

ins :: Ord a => a -> (Tree a) -> (Tree a)
ins a EmptyBST                  = Node a EmptyBST EmptyBST
ins a (Node p left right)
    | a < p                             = Node p (ins a left) right
    | a > p                             = Node p left (ins a right)
    | otherwise                             = Node p left right



lstToTree :: Ord a => [a] -> (Tree a)
lstToTree                   = foldr ins EmptyBST

fileRead                    = do    file    <- readFile "tree.txt"
                            let a = lstToTree (conv (words file))
                            return a

conv :: [String] -> [Int]
conv                        = map read
我得到了以下错误:

<interactive>:2:7:
    Couldn't match expected type `Tree a0'
                with actual type `IO (Tree Int)'
    In the second argument of `ins', namely `fileRead'
    In the expression: ins 5 fileRead
    In an equation for `it': it = ins 5 fileRead
:2:7:
无法匹配预期的类型“Tree a0”
实际类型为'IO(树Int)'
在'ins'的第二个参数中,即'fileRead'
在表达式中:ins 5 fileRead
在“it”的等式中:it=ins 5 fileRead
请问有人能帮我吗


谢谢

您无法真正逃离IO monad(除非通过不安全的函数),但在您的情况下,实际上不需要这样做:

main = do f <- fileRead
          let newtree = ins 5 f
          putStr $ show newtree

main=do f如果提供带有类型签名的
fileRead
,您将能够立即看到问题。让我们找出GHC将在内部分配给
fileRead
的类型注释:

fileRead = do file <- readFile "tree.txt"
              let t = lstToTree $ map read $ words file
              return t
因此,
fileRead
是一个用
IO
包装的
树,您不能将其直接传递到
ins
,因为它需要一个
树。您不能将
IO
中取出,但可以将函数
ins
提升到
IO
单子中

控制。单子导出。它接受一个常规函数,并将其转换为作用于monad(如
IO
)的函数。它实际上是(在标准前奏曲中)的同义词,因为所有的单子都是函子。因此,此代码大致相当于@us202,它获取
fileRead
的结果,插入
5
,并将结果包装在
IO
中返回

liftM (ins 5) fileRead
-- or --
fmap (ins 5) fileRead
我推荐
fmap
版本。这段代码只利用了
IO
是一个函子这一事实,因此使用
liftM
对读者意味着你可能也需要它是一个单子

“提升”是在单子或函子中包装的值上使用纯函数的一般技术。如果你不熟悉提升(或者你被单子和函子弄糊涂了),我衷心推荐本书的第11-13章


注意,
fileRead
的最后两行可能应该合并,因为
return
实际上没有任何作用:

fileRead :: (Read a, Ord a) => IO (Tree a)
fileRead = do file <- readFile "tree.txt"
           return $ lstToTree $ map read $ words file

根据您的评论编辑:

Haskell的设计目的是将执行IO的代码与常规代码分开。这有一个很好的哲学原因:大多数Haskell函数都是“纯的”——也就是说,它们的输出只依赖于输入,就像数学中的函数一样。你可以运行一个纯函数一百万次,结果总是一样的。我们喜欢纯函数,因为它们不会意外地破坏程序的其他部分,它们允许惰性,并且允许编译器积极地为您优化代码

当然,在现实世界中,我们需要一点杂质。像
getLine
这样的IO代码不可能是纯的(不执行IO的程序是无用的!)。
getLine
的结果取决于用户键入的内容:您可以运行
getLine
一百万次,每次都会得到不同的字符串。Haskell利用类型系统用类型
IO
标记不纯代码

liftM (ins 5) fileRead
-- or --
fmap (ins 5) fileRead
问题的关键在于:如果对不纯净的数据使用纯函数,那么结果仍然是不纯净的,因为结果取决于用户所做的。因此,整个计算属于
IO
monad。当您想将纯函数引入
IO
时,必须显式(使用
fmap
)或隐式(使用
do
表示法)将其提升


这是Haskell中非常常见的模式——看看我上面的
fileRead
。我已经使用
fmap
使用纯函数对不纯净的
IO
数据进行操作。

谢谢,但我希望用户输入他想要添加到列表中的任何元素。我不希望元素被修复,然后修改上面的内容:通过
getLine
读取元素,并使用它,添加某种循环来添加许多从stdin读取的元素,随你的便。问题是,我真正想做的是生成一个可以调用并返回Tree a类型元素的函数。即,它读取文本文件中的列表,通过lstToTree或类似工具生成一棵树,然后返回该树,以便用户可以在其上运行类似于ins的其他功能。“这能直接做到吗?”MohammedAl Farhan——这是一个非常好的问题,要做到公正,需要600多个字符。我已经更新了我的答案。
fileRead :: (Read a, Ord a) => IO (Tree a)
fileRead = do file <- readFile "tree.txt"
           return $ lstToTree $ map read $ words file
fileRead :: (Read a, Ord a) => IO (Tree a)
fileRead = fmap (lstToTree . map read . words) (readFile "tree.txt")