Haskell,结合Do和if

Haskell,结合Do和if,haskell,Haskell,嗨,我想知道是否有一种方法可以在haskell中以这种方式使用doif doIfFunction :: Eq a => [a]->[a] ->[a] doIfFunction l1 l2 = do if l /= something then (l2++something) else l2 if l /= something2 then (l2++something2) else l2 l2 基本上,如果这个something函数返回一个不同的值

嗨,我想知道是否有一种方法可以在haskell中以这种方式使用
do
if

doIfFunction :: Eq a => [a]->[a] ->[a]
doIfFunction l1 l2 = do
     if l /= something then (l2++something) else l2
     if l /= something2 then (l2++something2) else l2
     l2
基本上,如果这个something函数返回一个不同的值,我希望它将其添加到
l2
,然后返回
l2
。我一直认为
l2
最后是空的,它不应该是空的,这是因为
else l2
它是否将
l2
的值重置为开始时的值

如果是这样的话,我可以这样做吗

doIfFunction :: Eq a => [a]->[a] ->[a]
doIfFunction l1 l2 = do
     if l /= something then (let l2 = l2++something) else l2
     if l /= something2 then (let l2 = l2++something2) else l2
     l2
这会产生错误,但我想知道这是否正确


调用
doIfFunction
时,它将始终是
doIfFunction l[]
,其中
l
包含值且
[/code>为

只需在
let
语句中放入
if
子句即可:

doIfFunction :: Eq a => [a] -> [a] -> [a]
doIfFunction l1 l2 = do
    let l2'  = if l /= something  then l2  ++ something  else l2
    let l2'' = if l /= something2 then l2' ++ something2 else l2'
    l2''
但是在这种情况下,您并不真正需要
do
符号,因为您不使用任何一元运算。我相信您希望使用
do
符号来模拟命令式编程。考虑使用<<代码> >如果你认为它更可读:

doIfFunction :: Eq a => [a] -> [a] -> [a]
doIfFunction l1 l2 = result
    where newL2 = if l /= something  then l2 ++ something  else l2
        result = if l /= something2 then newL2 ++ something2 else newL2

或者,当您更熟悉Haskell时,您可以使用(这将是编写您想做的事情的最惯用方式)。

只需将
if
子句放在
let
语句中:

doIfFunction :: Eq a => [a] -> [a] -> [a]
doIfFunction l1 l2 = do
    let l2'  = if l /= something  then l2  ++ something  else l2
    let l2'' = if l /= something2 then l2' ++ something2 else l2'
    l2''
但是在这种情况下,您并不真正需要
do
符号,因为您不使用任何一元运算。我相信您希望使用
do
符号来模拟命令式编程。考虑使用<<代码> >如果你认为它更可读:

doIfFunction :: Eq a => [a] -> [a] -> [a]
doIfFunction l1 l2 = result
    where newL2 = if l /= something  then l2 ++ something  else l2
        result = if l /= something2 then newL2 ++ something2 else newL2

或者,当您更熟悉Haskell时,您可以使用(这是编写您想要做的事情的最惯用的方式)。

通常,您应该避免考虑修改Haskell中的任何内容。事实上,你不能,语言不允许。根本†

与其修改列表
l2
本身,不如考虑创建其他列表,这些列表是
l2
的修改版本。(直接的好处是,您仍然可以在其他任何地方使用原始的
l2
;特别是,如果其他函数/线程仍然需要此旧版本,而您不知道它,则可以使用此版本。)

即,代替

 do
   modify_something_about_l2
   modify_something_else_about_l2
   yield_some_result
您只需要评估函数应用程序链的结果,如

f l2 = some_other_modification (some_modification (l2))
或者,正如我们喜欢写的那样

f = some_other_modification . some_modification
在您的特殊情况下:

doIfFunction l1
  = (\l2 -> if l /= something2 then (l2++something2) else l2)
    . (\l2 -> if l /= something then (l2++something) else l2)
如果您不喜欢“向后样式”,也可以将合成运算符
替换为其翻转版本:

import Control.Arrow

doIfFunction l1
  = (\l2 -> if l /= something then (l2++something) else l2)
   >>> (\l2 -> if l /= something2 then (l2++something2) else l2)
此外,通过减少eta,您可以完全避免提及中间列表:

doIfFunction l1
  = (if l /= something then (++something) else id)
   >>> (if l /= something2 then (++something2) else id)

也就是说。。。 你可能会想:总是为所有东西创建新的修改版本,而不是原地修改,这是非常低效的

您的示例实际上是一个问题:要将
某物
附加到
l2
,需要制作整个列表的副本。也许您可以很容易地避免此问题:如果不附加,您可以预先添加:

这样就没有性能损失。原因是:列表只是一个元素链(head),每个元素都引用列表的其余部分。预挂起元素只是制作一个新的head并将其链接到已经存在的列表



†即使使用巧妙的延迟前置,有时纯函数式风格的时间开销也会显著增加。别担心:尽管Haskell不允许修改值,但仍有一些类型封装了破坏性修改的概念,即。因此,您仍然可以高效地实现需要破坏性更新的算法,但基本上,你不是在Haskell中做这件事,而是在一种嵌入式的“特定于域的命令式语言”中,它与Haskell无缝集成。

一般来说,你应该避免考虑修改Haskell中的任何内容。事实上,你不能,语言不允许这样做。根本†

与其修改列表
l2
本身,不如考虑创建其他列表,这些列表是
l2
的修改版本。(直接的好处是,您仍然可以在其他任何地方使用原始的
l2
;特别是,如果其他函数/线程仍然需要此旧版本,而您不知道它,则可以使用此版本。)

即,代替

 do
   modify_something_about_l2
   modify_something_else_about_l2
   yield_some_result
您只需要评估函数应用程序链的结果,如

f l2 = some_other_modification (some_modification (l2))
或者,正如我们喜欢写的那样

f = some_other_modification . some_modification
在您的特殊情况下:

doIfFunction l1
  = (\l2 -> if l /= something2 then (l2++something2) else l2)
    . (\l2 -> if l /= something then (l2++something) else l2)
如果您不喜欢“向后样式”,也可以将合成运算符
替换为其翻转版本:

import Control.Arrow

doIfFunction l1
  = (\l2 -> if l /= something then (l2++something) else l2)
   >>> (\l2 -> if l /= something2 then (l2++something2) else l2)
此外,通过减少eta,您可以完全避免提及中间列表:

doIfFunction l1
  = (if l /= something then (++something) else id)
   >>> (if l /= something2 then (++something2) else id)

也就是说。。。 你可能会想:总是为所有东西创建新的修改版本,而不是原地修改,这是非常低效的

您的示例实际上是一个问题:要将
某物
附加到
l2
,需要制作整个列表的副本。也许您可以很容易地避免此问题:如果不附加,您可以预先添加:

这样就没有性能损失。原因是:列表只是一个元素链(head),每个元素都引用列表的其余部分。预挂起元素只是制作一个新的head并将其链接到已经存在的列表


†即使使用巧妙的延迟前置,有时纯函数式风格的时间开销也会显著增加。别担心:尽管Haskell不允许修改值,但仍有一些类型封装了破坏性修改的概念,即。因此,您仍然可以高效地实现需要破坏性更新的算法,但基本上你不会在Haskell中做,而是在一个嵌入式的“特定于域的im”中做