gpt4 book ai didi

function - Haskell IO传递给另一个功能

转载 作者:行者123 更新时间:2023-12-02 19:38:33 27 4
gpt4 key购买 nike

这里的问题与
Haskell Input Return Tuple

我不知道我们如何将输入从monad IO传递到另一个函数,以便进行一些计算。

其实我想要的是

-- First Example
test = savefile investinput
-- Second Example
maxinvest :: a
maxinvest = liftM maximuminvest maxinvestinput

maxinvestinput :: IO()
maxinvestinput = do
str <- readFile "C:\\Invest.txt"
let cont = words str
let mytuple = converttuple cont
let myint = getint mytuple

putStrLn ""

-- Convert to Tuple
converttuple :: [String] -> [(String, Integer)]
converttuple [] = []
converttuple (x:y:z) = (x, read y):converttuple z

-- Get Integer
getint :: [(String, Integer)] -> [Integer]
getint [] = []
getint (x:xs) = snd (x) : getint xs

-- Search Maximum Invest
maximuminvest :: (Ord a) => [a] -> a
maximuminvest [] = error "Empty Invest Amount List"
maximuminvest [x] = x
maximuminvest (x:xs)
| x > maxTail = x
| otherwise = maxTail
where maxTail = maximuminvest xs

在第二个示例中,从文件中读取了maxinvestinput并将数据转换为预期的maxinvest类型。
请帮忙。

谢谢。

最佳答案

首先,我认为您在理解Haskell时遇到一些基本问题,因此让我们逐步进行构建。希望对您有所帮助。其中一些只会到达您拥有的代码,而某些不会到达您的代码,但这是我编写此代码时考虑的慢速版本。之后,我将尝试回答您的一个特定问题。

我不太确定您要让程序做什么。我知道您想要一个程序来读取包含人员及其投资清单的文件作为输入。但是,我不确定您要使用它做什么。您似乎(a)想要一个合理的数据结构([(String,Integer)]),但是(b)仅使用整数,因此我假设您也想对字符串做一些事情。让我们来看一下。首先,您需要一个函数,该函数可以在给定整数列表的情况下返回最大值。您将其称为maximuminvest,但是此功能更一般,仅用于投资,所以为什么不将其称为maximum呢?事实证明,该功能已经存在。你怎么知道我推荐Hoogle-这是一个Haskell搜索引擎,可让您搜索函数名称和类型。您需要一个从整数列表到单个整数的函数,所以让我们为search for that。事实证明,第一个结果是maximum,它是您想要的更通用的版本。但是出于学习目的,让我们假设您想自己编写它;在这种情况下,您的实现就可以了。

好了,现在我们可以计算最大值了。但是首先,我们需要构建列表。我们将需要一种[String] -> [(String,Integer)]类型的函数,以将我们的无格式列表转换为明智的列表。好吧,要从字符串中获取整数,我们需要使用read。长话短说,尽管我会(a)为单项列表添加error大小写(或者,如果我感觉很好,只是让它返回一个空列表以忽略最后一项),那么您当前的实现也可以(b)使用带有大写字母的名称,因此我可以将单词分开(可能使用不同的名称):

tupledInvestors :: [String] -> [(String, Integer)]
tupledInvestors [] = []
tupledInvestors [_] = error "tupledInvestors: Odd-length list"
tupledInvestors (name:amt:rest) = (name, read amt) : tupledInvestors rest

现在有了这些,我们可以为自己提供一个便捷函数 maxInvestment :: [String] -> Integer。唯一缺少的是从元组列表到整数列表的功能。有几种解决方法。一个就是您拥有的一个,尽管这在Haskell中并不常见。第二个是使用 map :: (a -> b) -> [a] -> [b]。这是将功能应用于列表的每个元素的功能。因此,您的 getint等效于更简单的 map snd。最好的方法可能是使用 Data.List.maximumBy :: :: (a -> a -> Ordering) -> [a] -> a。这类似于 maximum,但是它允许您使用自己的比较功能。并且使用 Data.Ord.comparing :: Ord a => (b -> a) -> b -> b -> Ordering,事情变得很好。通过此功能,您可以将两个任意对象转换为可以比较的对象,从而比较它们。因此,我会写
maxInvestment :: [String] -> Integer
maxInvestment = maximumBy (comparing snd) . tupledInvestors

虽然您也可以编写 maxInvestment = maximum . map snd . tupledInvestors

好了,现在进入IO。然后,您的主要功能想从特定文件中读取,计算最大投资并打印出来。一种表示方法是一系列三个不同的步骤:
main :: IO ()
main = do dataStr <- readFile "C:\\Invest.txt"
let maxInv = maxInvestment $ words dataStr
print maxInv

(如果没有看到 $运算符,它只是函数应用程序,但是具有更方便的优先级;它具有 (a -> b) -> a -> b类型,这应该是有道理的。)但是 let maxInv似乎毫无意义,因此我们可以摆脱这一点:
main :: IO ()
main = do dataStr <- readFile "C:\\Invest.txt"
print . maxInvestment $ words dataStr
.(如果您还没有看到的话)是函数组合。 f . g\x -> f (g x)相同。 (它的类型为 (b -> c) -> (a -> b) -> a -> c,在某种程度上应该是有道理的。)因此, f . g $ h xf (g (h x))相同,但更易于阅读。

现在,我们可以摆脱 let了。那 <-呢?为此,我们可以使用 =<< :: Monad m => (a -> m b) -> m a -> m b运算符。请注意,这几乎类似于 $,但 m几乎污染了所有内容。这使我们可以获取一个Monadic值(此处为 readFile "C:\\Invest.txt" :: IO String),并将其传递给一个将普通值转换为Monadic值的函数,并获得该Monadic值。因此,我们有
main :: IO ()
main = print . maxInvestment . words =<< readFile "C:\\Invest.txt"

我希望这应该很清楚,尤其是如果您将 =<<视为单子(monad) $

我不确定 testfile发生了什么;如果您编辑问题以反映该问题,我将尝试更新我的答案。

还有一件事。你说

我不知道我们如何将输入从monad IO传递到另一个函数,以便进行一些计算。

与Haskell中的所有内容一样,这也是类型问题。因此,让我们对这里的类型感到困惑。您有一些函数 f :: a -> b和一些monadic值 m :: IO a。您想使用 f来获取 b类型的值。正如我在 my answer to your other question中解释的那样,这是不可能的。但是,您可以得到 IO b类型的东西。因此,您需要一个函数,该函数接受 f并给您单子(monad)版本。换句话说,类型为 Monad m => (a -> b) -> (m a -> m b)的东西。如果我们 plug that into Hoogle,则第一个结果是 Control.Monad.liftM,它具有该类型签名。因此,您可以将 liftM视为与 $略有不同的“monadic =<<”: f `liftM` mf应用于 m的纯结果(根据您所使用的monad),并返回monadic结果。不同之处在于 liftM在左侧采用了纯函数,而 =<<采用了部分单子(monad)函数。

编写相同内容的另一种方法是使用 do -notation:
do x <- m
return $ f x

这就是说:“从 x中取出 m,对其应用 f,然后将结果提升回monad。”这与 return . f =<< m语句相同,再次是 liftM。首先 f执行一次纯计算;其结果被传递到 return(通过 .),这将纯净值提升到monad中;然后通过 =<,将此部分monadic函数应用于 m

已经很晚了,所以我不确定这样做的意义。让我尝试总结一下。简而言之,没有一般的方法可以离开单子(monad)。当您想对单子(monad)值执行计算时,可以将纯值(包括函数)提升到单子(monad)中,而不是相反。可能会违反纯度,这将是Very Bad™。

我希望这能真正回答您的问题。让我知道是否可以,所以我可以尝试使它更有用!

关于function - Haskell IO传递给另一个功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3067786/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com