首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在MonadState中使用透镜的一些潜在和困难

在MonadState中使用透镜的一些潜在和困难
EN

Stack Overflow用户
提问于 2014-05-02 19:35:52
回答 2查看 205关注 0票数 1

下面是一系列关于镜头的例子/练习(由Edward )在MonadState中,基于Pudlak对我之前的问题的解答。

除了演示镜头的一些用途和威力外,这些示例还显示了理解GHCi生成的类型签名是多么困难。还有希望在未来的事情会有所改善吗?

代码语言:javascript
复制
{-# LANGUAGE TemplateHaskell, RankNTypes #-}

import Control.Lens
import Control.Monad.State

---------- Example by Petr Pudlak   ----------
-- | An example of a universal function that modifies any lens.
-- It reads a string and appends it to the existing value.
modif :: Lens' a String -> StateT a IO ()
modif l = do
    s <- lift getLine
    l %= (++ s)

-----------------------------------------------

下面的注释类型签名是由GHCi生成的签名。另一种是彼得的改编。就我个人而言,我比GHCi所产生的更难理解,我想知道:为什么GHCi不产生那些简化的?

代码语言:javascript
复制
-------------------------------------------

-- modif2
  -- :: (Profunctor p, MonadTrans t, MonadState s (t IO)) =>
     -- (Int -> p a b) -> Setting p s s a b -> t IO ()
modif2 :: (Int -> Int -> Int) -> Lens' a Int -> StateT a IO ()     
modif2 f l = do
    s<- lift getLine
    l %= f (read s :: Int)

---------------------------------------

-- modif3
  -- :: (Profunctor p, MonadTrans t, MonadState s (t IO)) =>
     -- (String -> p a b) -> Setting p s s a b -> t IO ()
modif3 :: (String -> Int -> Int) -> Lens' a Int -> StateT a IO ()     
modif3 f l = do
    s <- lift getLine
    l %= f s
-- :t modif3 (\n -> (+) (read n :: Int)) == Lens' a Int -> StateT a IO ()

---------------------------------------

-- modif4 
  -- :: (Profunctor p, MonadTrans t, MonadState s (t IO)) =>
     -- (t1 -> p a b) -> (String -> t1) -> Setting p s s a b -> t IO ()
modif4 :: (Bool -> Bool -> Bool) -> (String -> Bool) -> Lens' a Bool -> StateT a IO ()
modif4 f f2 l = do
    s <- lift getLine
    l %= f (f2 s)
-- :t modif4 (&&) (\s -> read s :: Bool) == Lens' a Bool -> StateT a IO ()

---------------------------------------
-- modif5
  -- :: (Profunctor p, MonadTrans t, MonadState s (t IO)) =>
     -- (t1 -> p a b) -> (String -> t1) -> Setting p s s a b -> t IO ()
modif5 :: (b -> b -> b) -> (String -> b) -> Lens' a b -> StateT a IO ()
modif5 f f2 l = do
    s<- lift getLine
    l %= f (f2 s)
-- :t modif5 (&&) (\s -> read s :: Bool) == Lens' a Bool -> StateT a IO ()

---------------------------------------

-- modif6
  -- :: (Profunctor p, MonadState s m) =>
     -- (t -> p a b) -> (t1 -> t) -> t1 -> Setting p s s a b -> m ()
modif6 :: (b -> b -> b) -> (c -> b) -> c -> Lens' a b -> StateT a IO ()
modif6 f f2 x l = do
    l %= f (f2 x)
-- :t modif6 (&&) (\s -> read s :: Bool) "True" ==  MonadState s m => Setting (->) s s Bool Bool -> m ()
-- :t modif6 (&&) (\s -> read s :: Bool) "True" 

---------------------------------------

-- modif7
  -- :: (Profunctor p, MonadState s IO) =>
     -- (t -> p a b) -> (String -> t) -> Setting p s s a b -> IO ()
modif7 :: (b -> b -> b) -> (String -> b) -> Lens' a b -> StateT a IO ()
modif7 f f2 l = do
    s <- lift getLine
    l %= f (f2 s)
-- :t modif7 (&&) (\s -> read s :: Bool) == 
-- :t modif7 (+) (\s -> read s :: Int) == 

---------------------------------------

p7a :: StateT Int IO ()
p7a = do
  get
  modif7 (+) (\s -> read s :: Int) id

test7a = execStateT p7a 10  -- if input 30 then result 40

---------------------------------------

p7b :: StateT Bool IO ()
p7b = do
  get
  modif7 (||) (\s -> read s :: Bool) id

test7b = execStateT p7b False  -- if input "True" then result "True"

---------------------------------------

data Test = Test { _first :: Int
                 , _second :: Bool
                 }
    deriving Show

$(makeLenses ''Test)

dataTest :: Test
dataTest = Test  { _first = 1, _second = False }

monadTest :: StateT Test IO String
monadTest = do
  get
  lift . putStrLn $ "1) modify \"first\" (Int requested)"
  lift . putStrLn $ "2) modify \"second\" (Bool requested)"
  answ <- lift getLine
  case answ of
    "1" -> do lift . putStr $ "> Write an Int: "
              modif7 (+) (\s -> read s :: Int) first
    "2" -> do lift . putStr $ "> Write a Bool: "
              modif7 (||) (\s -> read s :: Bool) second
    _   -> error "Wrong choice!"
  return answ

testMonadTest :: IO Test  
testMonadTest = execStateT monadTest dataTest
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-05-02 19:50:22

作为ML传统中的一个家族,Haskell是专门设计的,这样每个toplevel绑定都有一个最通用的类型,并且Haskell实现可以而且必须推断出这种最通用的类型。这确保了您可以在尽可能多的地方重用绑定。在某种程度上,这意味着类型推断永远不会出错,因为无论您想到哪种类型,类型推断都会找出相同的类型或更一般的类型。

为什么GHCi不产生那些简化的?

它反而找出了更一般的类型。例如,您提到GHC为某些代码确定了以下类型:

代码语言:javascript
复制
modif2 :: (Profunctor p, MonadTrans t, MonadState s (t IO)) =>
  (Int -> p a b) -> Setting p s s a b -> t IO ()

这是一种非常普遍的类型,因为每次我使用modif2时,我都可以选择不同的p、单端变压器t和状态s。所以modif2是非常可重用的。您更喜欢这种类型的签名:

代码语言:javascript
复制
modif2 :: (Int -> Int -> Int) -> Lens' a Int -> StateT a IO ()     

我同意这更易读,但也不那么通用:这里您决定p必须是->t必须是StateT,而作为modif2的用户,我无法改变这一点。

还有希望在未来的事情会有所改善吗?

我确信,作为类型推断的结果,Haskell将继续强制大多数一般类型。我可以想象,除了最通用的类型之外,ghci或第三方工具还可以向您展示示例实例化。在这种情况下,最好以某种方式声明->是一个典型的终止函数。我不知道在这个方向上有什么工作,所以没有太多的希望,没有。

票数 5
EN

Stack Overflow用户

发布于 2014-05-02 20:05:52

让我们看一下第一个例子:

代码语言:javascript
复制
modif :: Lens' a String -> StateT a IO ()
modif l = do
  s <- lift getLine
  l %= (++ s)

这种类型很简单,但也有一个缺点:您只能使用传递Lens的函数。您不能使用您的函数,当您有一个Iso是一个Traversal,即使这将是完全合理的!考虑到GHCi推断的更一般的类型,例如,您可以编写以下内容:

代码语言:javascript
复制
modif _Just :: StateT (Maybe String) IO ()

只有在状态为Just时才会追加读值,或者

代码语言:javascript
复制
modif traverse :: StateT [String] IO ()

它将将读值附加到列表中的所有元素。对于你给出的简单类型来说,这是不可能的,因为_Justtraverse不是透镜,而是Traversals

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23435676

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档