我需要这个用于我的作业,我已经完成了我的解决方案,但我还有最后一个子问题,我无法弄清楚如何解决..
Clean-Rebuild-Run
所以我试图通过这个功能实现的是: 拿一棵树,将树映射到自己,但将参数mi改为(transformNote mi 2)。
此代码按预期工作并执行所有操作,但我实际需要的是一个函数
type Notes = [(Int,Int,Int,Int)]
data Tree = Leaf Notes | Node Notes [Tree]]
deriving(Eq,Show)
identity :: Tree -> Tree
identity (Leaf mi ) = Leaf (transformNote mi 2)
identity (Node mi xs) = Node (transformNote mi 2) (map identity xs)
这样我的功能变成了这样的东西:
identity :: Tree -> Int -> Tree
自
以来这不起作用identity :: Tree -> Int -> Tree
identity (Leaf mi ) amount = Leaf (transformNote mi amount)
identity (Node mi xs) amount = Node (transformNote mi amount) (map identity xs amount)
我尝试了很多方法来解决这个问题,在条款周围抛出金额变量但似乎没有任何效果。我无法理解为什么我的解决方案都不起作用。
有人可以帮忙吗? THX
答案 0 :(得分:2)
如果你概括一下,这实际上更容易。将Tree
参数化,使其成为Functor
的实例:
data Tree a = Leaf a | Node a [Tree a] deriving (Eq,Show)
instance Functor Tree where
fmap f (Leaf x) = Leaf (f x)
fmap f (Node x xs) = Node (f x) (fmap (fmap f) xs)
现在你可以根据自己的需要转换Tree
的元素:
identity :: Tree Notes -> Int -> Tree Notes
identity t amount = fmap (\n -> transformNote n amount) t
顺便说一句,identity
是函数的错误名称,因为通过数学(和Haskell)约定,标识函数是
id :: a -> a
id x = x
即,简单地返回其参数的函数。
答案 1 :(得分:1)
所有子树s
,需要替换为identity s amount
。这意味着我们可以编写 lambda表达式 \s -> identity s amount
,从而转换单个子树。然后我们可以在map
:
identity :: Tree -> Int -> Tree
identity (Leaf mi ) amount = Leaf (transformNote mi amount)
identity (Node mi xs) amount = Node nmi (map (\s -> identity s amount) xs)
where nmi = transformNote mi amount
where
子句仅用于使代码适合可用的页面宽度。
但这很难看。我们可以使用翻转这两个参数的https://developer.mozilla.org/en-US/docs/Web/API/Position。在这种情况下,我们可以将其写成:
identity :: Tree -> Int -> Tree
identity (Leaf mi ) amount = Leaf (transformNote mi amount)
identity (Node mi xs) amount = Node nmi (map (flip identity amount) xs)
where nmi = transformNote mi amount
因为它经常引入丑陋的表达,这就是为什么在Haskell中通常会翻转参数本身的原因之一:
-- flipped version
identity2 :: Int -> Tree -> Tree
identity2 amount (Leaf mi ) = Leaf (transformNote mi amount)
identity2 amount (Node mi xs) = Node nmi (map (identity2 amount) xs)
where nmi = transformNote mi amount