Haskell,结合Do和if
嗨,我想知道是否有一种方法可以在haskell中以这种方式使用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函数返回一个不同的值
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”中做