Haskell中fromjust的理由

Dai*_*san 4 monads haskell maybe

我正在努力学习Haskll,所以我在Haskell中尝试了Project Euler的问题26:http: //projecteuler.net/problem=26

我对这个问题的解决方案是这样的:

answer26 = answer26' 1000
answer26' n = snd $ maximum $ map (\x -> cycleLength x [1]) [2..n - 1]
    where
    cycleLength n (r:rs)
        | i /= Nothing      = (1 + fromJust i, n)
        | r < n             = cycleLength n $ (10*r):r:rs
        | otherwise         = cycleLength n $ (r `mod` n):r:rs
        where i = elemIndex r rs
Run Code Online (Sandbox Code Playgroud)

我意识到这不是最有效的算法,但看到它是天真的O(n ^ 3)(其中n = 1000)不是这样的问题.我关心的是,根据我对monad的理解,他们的主要特性之一是它们在某种意义上"标记"任何使用过monad的东西.功能"fromJust"似乎直接面对它.它为什么存在?另外,假设它的存在是合理的,我在上面的代码中使用它是否很好?

Pet*_*all 11

通常不鼓励使用部分函数(可能不返回值的函数).功能喜欢headfromJust存在,因为他们偶尔会方便; 你有时可以编写更短的代码,这对学习者来说更容易理解.许多功能算法用head和表示,tail并且fromJust在概念上与它们相同head.

通常最好使用模式匹配,并避免部分函数,​​因为它允许编译器为您捕获错误.在您的代码片段中,您仔细检查过该值永远不会Nothing,但在大型现实代码库中,代码可能需要很多年,1000多行代码并且由许多开发人员维护.开发人员很容易重新订购一些代码并错过这样的支票.通过模式匹配,它就在代码结构中,而不仅仅是在一些任意的Bool表达式中.

fromJust用模式匹配替换你的用法并不太难:

answer26 = answer26' 1000
answer26' n = snd $ maximum $ map (\x -> cycleLength x [1]) [2..n - 1]
    where
    cycleLength n (r:rs) = case elemIndex r rs of
            Just i  -> (1 + i, n)
            Nothing -> if r < n
                        then cycleLength n $ (10*r):r:rs
                        else cycleLength n $ (r `mod` n):r:rs
Run Code Online (Sandbox Code Playgroud)

而且(我认为)结果也更加清晰.

编辑:fromJustTypeclassopedia中有一个显然"理论上可以"使用的地方,虽然你需要我以外的其他人解释wtf,这是关于..;)


dan*_*iaz 10

monad接口不包含任何用于从monad中"提取"值的特定函数,仅用于将它们放入(return)中.

但是,它也没有禁止这些功能.当他们的存在,他们将具体到每个单子(的运行*功能,因此众人:runIdentity,runReader,runWriter,runState.......每一个不同的参数)

根据设计,IO没有任何这样的"离开"功能,因此它用于"捕获"monad中的不纯值.但是"不能出去"并不是一般的单身人士的要求.重要的是他们尊重monad法律.

对于comonads,情况正好相反.有一个通用函数可以从extract每个comonad必须实现的值()中提取值.但是,"存在价值"的功能,当它们存在时,每个特定的comonad(env,store ......)都有所不同.

至于fromJust,最好尽可能避免它,因为它是一个在运行时可能无法匹配的部分函数.