use*_*011 5 implementation haskell applicative type-signature
我最近看到一个简单的例子,它揭示了<*和*>。
validate :: String -> Maybe String
validate s = if s=="" then Nothing else Just s
>validate "a" *> validate "b"
Just "b"
>validate "" *> validate "b"
Nothing
>validate "a" <* validate "b"
Just "a"
>validate "a" <* validate ""
Nothing
>validate "a" <* validate "b" <* validate "c"
Just "a"
>validate "a" *> validate "b" <* validate "c"
Just "b"
Run Code Online (Sandbox Code Playgroud)
这表明,即使其产生的价值并不重要,但其效果却很重要。
我的问题是关于类型签名。
(*>) :: f a -> f b -> f b
(<*) :: f a -> f b -> f a
Run Code Online (Sandbox Code Playgroud)
我可以看到人们如何推理“显然我们有一个 Applicative - 所以这说明了一般行为。对于运算符*>,由于我们丢弃了左值,因此该函数唯一可能的含义是该函数的效果如何左侧影响整个操作。”
在这种情况下Maybe——那么似乎是的——该行为是隐含的。对于Either,同样,该蕴涵成立,并且错误将在效果“失败”时传播。
请注意,我只能说上述内容,因为我现在知道实现是如何工作的,我的问题涉及经验丰富的函数程序员,他们第一次看到这样的签名。
我读过类似的类型签名[a] -> b :: Int(可能不是真正的代码),但暗示了列表长度的实现。
我还搜索了“暗示从类型签名实现”,发现人们已经/正在研究这样的事情 - 但一般来说无法完成(呃 - 没有新的 GitHub 东西:--)
所以也许我已经回答了我自己的问题,但希望有任何其他答案或评论。我对 Haskell 还是个新手,多年来经历了一些错误的开始,终于开始理解它了。而我只触及了表面......
谢谢
Run Code Online (Sandbox Code Playgroud)(*>) :: f a -> f b -> f b (<*) :: f a -> f b -> f a这些类型签名实际上意味着上面显示的行为吗?
当然不是。这两个操作可以简单地实现为
apR :: (Applicative f) => f a -> f b -> f b
apR a b = b
apL :: (Applicative f) => f a -> f b -> f a
apL a b = a
Run Code Online (Sandbox Code Playgroud)
只是忽略了Applicative对 的约束f。
并且以同样的方式[a] -> Int并不意味着正在实施length。也可以是
foo :: [a] -> Int
foo _ = 42
Run Code Online (Sandbox Code Playgroud)
但在这两种情况下,这些都不是“正确”的实现,因为推断的类型与给定的签名不同。
那么你的问题也许有点不同,比如,假设有一个具有匹配推断类型的实现。这是否意味着它做了我们想要做的事情?
答案似乎仍然是否定的。其一,我们可以定义
apR2 :: (Applicative f) => f a -> f b -> f b
apR2 a b = pure (\a _ b -> b) <*> a <*> b <*> b
Run Code Online (Sandbox Code Playgroud)
对于某些类型,例如您的示例,这不会产生任何影响。但一般来说,执行两次效果与仅执行一次不同。
另一个更有意义的“错误”实现(感谢Daniel Wagner的评论)是
apR2b :: (Applicative f) => f a -> f b -> f b
apR2b a b = pure (\b a -> b) <*> b <*> a
Run Code Online (Sandbox Code Playgroud)
现在,即使你的例子也并不总是有效,因为效果的顺序不同——它b先“执行”,然后再a执行。