Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.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 如何从不纯方法返回纯值_Haskell_Monads_Functor - Fatal编程技术网

Haskell 如何从不纯方法返回纯值

Haskell 如何从不纯方法返回纯值,haskell,monads,functor,Haskell,Monads,Functor,我知道这听起来很琐碎,但我想知道如何从函子中展开一个值并将其作为纯值返回 我试过: f::IO a->a f x=(x>>=) f= >>= 我应该在右边放什么?我不能使用return,因为它会再次将其包装回去。它很简单,所以这将是一个很长的答案。简而言之,问题在于签名,ioa->a,不是Haskell中正确允许的类型。这实际上与IO是一个函子关系不大,而与IO是一个特殊的事实关系不大 对于某些函子,可以恢复纯值。例如,一个部分应用的对,(,)a,是一个函子。

我知道这听起来很琐碎,但我想知道如何从函子中展开一个值并将其作为纯值返回

我试过:

f::IO a->a
f x=(x>>=) 

f= >>=

我应该在右边放什么?我不能使用
return
,因为它会再次将其包装回去。

它很简单,所以这将是一个很长的答案。简而言之,问题在于签名,
ioa->a
,不是Haskell中正确允许的类型。这实际上与
IO
是一个函子关系不大,而与
IO
是一个特殊的事实关系不大

对于某些函子,可以恢复纯值。例如,一个部分应用的对,
(,)a
,是一个函子。我们通过
snd
打开值

snd :: (a,b) -> b
snd (_,b) = b
这是一个函子,我们可以把它展开成一个纯值,但这与函子的性质无关。它更多地涉及属于不同范畴理论概念的配对,包括:

任何
Comonad
都将是一个函子,您可以为其恢复纯值

许多(非同位语)functor都有——比如说“evaluators”——它们允许类似于被询问的内容。例如,我们可以使用
Maybe::a->Maybe a->a
评估
Maybe
。通过提供默认值,
可能a
具有所需的类型,
可能a->a
。另一个有用的例子是,
evalState::State sa->s->a
,它的参数颠倒了,但概念是相同的;给定monad,
状态sa
,初始状态,
s
,我们打开纯值,
a

最后是
IO
的细节。Haskell语言或库中没有为IO提供“evaluator”。我们可能会认为运行程序本身是一个评估器——与“代码> ValueSt/<代码>完全相同。但是如果这是一个有效的概念性动作,那么它只会帮助你确信没有一种明智的方法可以从
IO
中展开——任何编写的程序都只是其求值函数的
IO a
输入

相反,您被迫做的是在
IO
monad中工作。例如,如果你有一个纯函数,
f::a->b
,你可以通过,
fmap f::IO a->IO b


TL;DR您无法从
IO
monad中获得纯值。在
IO
上下文中应用纯函数,例如通过
fmap

这是一个常见问题:如何从monad中提取“the”值,不仅在Haskell中,而且在其他语言中也是如此。我有一个关于为什么这个问题不断出现的理论,所以我将试着根据这个理论来回答;我希望有帮助

单值容器 您可以将函子(因此也是单子)视为值的容器。这在(冗余)
Identity
functor中最为明显:

Prelude Control.Monad.Identity> Identity 42
Identity 42
这只是一个值的包装,在本例中是
42
。对于此特定容器,您可以提取值,因为它保证存在:

Prelude Control.Monad.Identity> runIdentity $ Identity 42
42
虽然
Identity
似乎毫无用处,但您可以找到其他似乎只包含一个值的functor。例如,在F#中,您经常会遇到像
Async
这样的容器,它们用于表示异步或惰性计算(Haskell不需要后者,因为默认情况下它是惰性的)

在Haskell中,您会发现许多其他单值容器,例如
Sum
Product
Last
First
Max
Min
,等等。所有这些容器的共同点是它们包装一个值,这意味着您可以提取值

我认为当人们第一次遇到函子和单子时,他们倾向于这样看待数据容器的概念:作为一个单一值的容器

可选值的容器 不幸的是,哈斯克尔的一些常见单子似乎支持这一观点。例如,
可能也是一个数据容器,但它可以包含零或一个值。不幸的是,如果值存在,您仍然可以提取该值:

Prelude Data.Maybe> fromJust $ Just 42
42
这样做的问题是
fromJust
不是total,因此如果使用
Nothing
值调用它,它将崩溃:

Prelude Data.Maybe> fromJust Nothing
*** Exception: Maybe.fromJust: Nothing
您可以在
中看到相同类型的问题。虽然我不知道有一个内置的分部函数来提取
Right
值,但您可以轻松编写一个模式匹配函数(如果忽略编译器警告):

同样,它在“快乐之路”场景中工作,但也很容易崩溃:

Prelude> extractRight $ Right 42
42
Prelude> extractRight $ Left "foo"
*** Exception: <interactive>:12:1-26: Non-exhaustive patterns in function extractRight
不过,它可能会失败:

Prelude> head []
*** Exception: Prelude.head: empty list
然而,在这一点上,很明显,试图从任意函子中提取“the”值是毫无意义的。列表是一个函子,但它包含任意数量的值,包括零和无限多个值

不过,您总是可以编写将“包含”值作为输入并返回另一个值作为输出的函数。下面是此类函数的任意示例:

countAndMultiply :: Foldable t => (t a, Int) -> Int
countAndMultiply (xs, factor) = length xs * factor
虽然无法从列表中“提取值”,但可以将函数应用于列表中的每个值:

Prelude> fmap countAndMultiply [("foo", 2), ("bar", 3), ("corge", 2)]
[6,9,10]
由于
IO
是一个函子,因此您也可以对其执行相同的操作:

Prelude> foo = return ("foo", 2) :: IO (String, Int)
Prelude> :t foo
foo :: IO (String, Int)
Prelude> fmap countAndMultiply foo
6
关键是,你不需要从一个函子中提取一个值,你需要进入这个函子

单子 有时,应用于函子的函数返回已包装在同一数据容器中的值。例如,您可能有一个将字符串拆分为特定字符的函数。为了简单起见,让我们看看将字符串拆分为单词的内置函数
words

Prelude> words "foo bar"
["foo","bar"]
如果您有一个字符串列表,并对每个字符串应用
单词
,您将得到一个嵌套列表:

Prelude> fmap words ["foo bar", "baz qux"]
[["foo","bar"],["baz","qux"]]
结果是一个嵌套的数据容器,在本例中是一个列表列表。你可以用手把它压平
Prelude> foo = return ("foo", 2) :: IO (String, Int)
Prelude> :t foo
foo :: IO (String, Int)
Prelude> fmap countAndMultiply foo
6
Prelude> words "foo bar"
["foo","bar"]
Prelude> fmap words ["foo bar", "baz qux"]
[["foo","bar"],["baz","qux"]]
Prelude Control.Monad> join $ fmap words ["foo bar", "baz qux"]
["foo","bar","baz","qux"]