我是函数式编程的新手,最近在Learn You a Haskell学习,但是当我完成本章时,我遇到了以下程序:
import Control.Monad.Writer
logNumber :: Int -> Writer [String] Int
logNumber x = Writer (x, ["Got number: " ++ show x])
multWithLog :: Writer [String] Int
multWithLog = do
a <- logNumber 3
b <- logNumber 5
return (a*b)
Run Code Online (Sandbox Code Playgroud)
我将这些行保存在.hs文件中,但无法将其导入我的ghci,抱怨:
more1.hs:4:15:
Not in scope: data constructor `Writer'
Perhaps you meant `WriterT' (imported from Control.Monad.Writer)
Failed, modules loaded: none.
Run Code Online (Sandbox Code Playgroud)
我通过":info"命令检查了类型:
Prelude Control.Monad.Writer> :info Writer
type Writer w = WriterT w Data.Functor.Identity.Identity
-- Defined in …
Run Code Online (Sandbox Code Playgroud) 我想把二叉树拉链作为comonad的一个实例,但我无法弄清楚如何duplicate
正确实现.
这是我的尝试:
{-# LANGUAGE DeriveFunctor #-}
import Data.Function
import Control.Arrow
import Control.Comonad
data BinTree a
= Leaf a
| Branch a (BinTree a) (BinTree a)
deriving (Functor, Show, Eq)
data Dir = L | R
deriving (Show, Eq)
-- an incomplete binary tree, aka data context
data Partial a = Missing Dir (BinTree a) a
deriving (Show, Eq, Functor)
-- BTZ for BinTree Zipper
newtype BTZ a = BTZ { getBTZ :: ([Partial a], BinTree a) }
deriving …
Run Code Online (Sandbox Code Playgroud) 假设我有一个状态monad,我想对状态进行一些操作,并且可能希望在将来撤消更改.我一般可以这样做得体面吗?
举一个具体的例子,让我们假设状态只是一个Int
,操作就是将数字增加一个.
type TestM a = StateT a IO ()
inc :: TestM Int
inc = modify (+ 1)
Run Code Online (Sandbox Code Playgroud)
但是,如果我想跟踪状态的所有历史记录,以防我想要撤消到某个先前的状态,我能想到的最好的方法是将状态包装在堆栈中:对状态的每次修改都会被推送到堆栈,以便我可以通过删除堆栈上的顶部元素来撤消更改.
-- just for showing what's going on
traceState :: (MonadIO m, MonadState s m, Show s) => m a -> m a
traceState m = get >>= liftIO . print >> m
recordDo :: TestM a -> TestM [a]
recordDo m = do
x <- gets head
y <- liftIO $ execStateT m x
modify (y:)
inc' :: …
Run Code Online (Sandbox Code Playgroud) 我试图扭转一个列表.
以下是我的代码:
reverseList :: [Int] -> [Int]
reverseList [] = []
reverseList (x:xs) = x:reverseList xs
Run Code Online (Sandbox Code Playgroud)
最终发生的事情是我最终以相同的顺序返回列表.我甚至有一个如何扭转列表的解决方案,但我想知道我在这里做错了什么?我对haskell很新,所以我认为我应该专注于理解更多,然后我可以轻松解决更多问题.我知道有很多解决方案可以解决这个问题,但我需要更多的帮助来理解我在这段代码中做错了什么.
我想知道是否有一般方法在ad-hoc多态函数和参数多态函数之间进行转换.换句话说,给定一个ad-hoc多态函数,如何实现其参数对应?反过来呢?
取sort
,例如,它很容易写sort :: Ord a => [a] -> [a]
在以下方面sortBy
:
sort :: Ord a => [a] -> [a]
sort = sortBy compare
Run Code Online (Sandbox Code Playgroud)
但另一种方式似乎很棘手,到目前为止,我能做的最好的事情是有点"面向对象":
import qualified Data.List as L
data OrdVal a = OV (a -> a -> Ordering) a
instance Eq (OrdVal a) where
(OV cmp a) == (OV _ b) = a `cmp` b == EQ
instance Ord (OrdVal a) where
(OV cmp a) `compare` (OV _ b) = a `cmp` b
sortBy :: …
Run Code Online (Sandbox Code Playgroud) reflection haskell parametric-polymorphism adhoc-polymorphism
当我浏览LYAH的最后一章并与ListZipper会面时,我给了自己一个使它成为状态monad的任务,以便源代码看起来更清晰如下:
manipList = do
goForward
goForward
goBack
Run Code Online (Sandbox Code Playgroud)
同时,我想通过利用Writer monad保留这个过程的日志,但我不知道如何将这两个Monad组合在一起.
我的解决方案是在状态中保留一个[String],我的源代码是
import Control.Monad
import Control.Monad.State
type ListZipper a = ([a], [a])
-- move focus forward, put previous root into breadcrumbs
goForward :: ListZipper a -> ListZipper a
goForward (x:xs, bs) = (xs, x:bs)
-- move focus back, restore previous root from breadcrumbs
goBack :: ListZipper a -> ListZipper a
goBack (xs, b:bs) = (b:xs, bs)
-- wrap goForward so it becomes a State
goForwardM :: State (ListZipper a) [a] …
Run Code Online (Sandbox Code Playgroud) (提前抱歉,我不知道如何更好地表达这个问题)
假设我有这样的数据类型:
data Foo = A | B
Run Code Online (Sandbox Code Playgroud)
现在我想要一对Foo
,带有禁止的约束(A, A)
。
我可以采用简单的方法,将它们全部列出来,如下所示:
data Foo2 = AB | BA | BB
Run Code Online (Sandbox Code Playgroud)
但正如你所看到的,这很快就会失控:如果我们想要 n 元组怎么办Foo
?或者如果有更多的选择怎么办Foo
?
当然,另一种选择是使用newtype
智能构造函数
newtype Foo2 = Foo2 (Foo, Foo)
mkFoo2 xy = Foo2 xy <$ guard (xy /= (A,A))
Run Code Online (Sandbox Code Playgroud)
但这在某种意义上是“不准确的”,因为当我们析构时Foo2
,我们总是必须处理实际上无法访问的情况,但编译器没有这样的知识:
...
case v :: Foo2 of
...
Foo2 (A, A) -> error "unreachable"
...
Run Code Online (Sandbox Code Playgroud)
我的问题是,是否有更好的方法来准确表示“Foo 的 n 元组,其中某些组合,例如(A,A)
或(A,B,C)
(当n=3
)不可能”的想法?
附带问题:减法/求反是代数数据类型中的一件事吗?Foo^n - (forbidden …
我最近正在探索递归方案,想要找到一些组织同态的用例 - 我认为加泰罗尼亚数字可能是一个有趣的例子(我知道有更好的方法来实现加泰罗尼亚数字,这不是本文的重点问题)。我的想法如下:
import Control.Comonad.Cofree
import Control.Monad
import Data.Foldable
import Data.Function.Memoize (memoFix)
import Data.Functor.Foldable
import GHC.Natural
type Nat = Natural
-- unrelated lines omitted
catalanHisto :: Nat -> Nat
catalanHisto = histo \case
Nothing ->
1
Just fs ->
let xs = toList fs -- this is line 101 in my original code.
ys = reverse xs
in sum $ zipWith (*) xs ys
catalanMemo :: Integer -> Integer
catalanMemo = memoFix \q n ->
if …
Run Code Online (Sandbox Code Playgroud) 这个问题可以在这里找到.
在书中,我发现正常订单评估的一个描述是:
"另一种评估模型不会在需要它们的值之前评估操作数.相反,它首先将操作数表达式替换为参数,直到它获得仅涉及原始运算符的表达式,然后执行评估."
我还简要地找到了另一种描述:"完全扩展然后减少".
在练习中,我认为定义p
是类似的(lambda () (p))
,它永远不会扩展到原始操作符,因此永远不会终止.
然而,另一方面,在搜索到这个问题的一些答案之后,似乎正常的订单评估应该终止,因为它只根据需要评估事物,实际上(p)
不会被评估.
所以我认为"扩展"和"评估"之间必然存在一些差异,而解释者在这里做的是评估事物.
究竟有什么区别,或者我错过了哪些观点?
另一个问题:我应该说" (p)
被评估为(p)
"还是" (p)
被扩展为(p)
"?
当我编写Haskell代码时,我在emacs中使用flycheck和haskell-hlint,我认为如果我可以通过调用一些emacs程序而不是手动修改代码来应用这些hlint建议会很棒.
如果没有可用的,以防我必须为自己编写此程序:
是否保证hlint输出始终为以下形式:
Found:
{Text1}
Why not:
{Text2}
Run Code Online (Sandbox Code Playgroud)
哪里{Text?}
可以始终解析为Haskell抽象语法树?